SpringBoot 我的项目创立
创立 Module
基于 IDEA 创立我的项目 Module, 模块名为 04-springboot-start, 组 id 和包名为 com.cy, 如图所示:
填写 module 信息, 如图所示:
抉择我的项目 module 版本, 临时不须要本人手动增加任何依赖, 如图所示:
填写 Module 名称, 实现 module 创立, 如图所示
我的项目构造剖析
我的项目 Module 创立好当前,其代码构造剖析,如图所示:
SpringBoot 我的项目启动剖析
启动入口
SpringBoot 工程中由 SpringBootApplication 注解形容的类为启动入口类,例如:
package com.cy;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {//Application.class
public static void main(String[] args) {//Main Thread
SpringApplication.run(Application.class, args);
}
}
启动过程概要剖析
SpringBoot 工程启动时其繁难初始化过程,如图所示:
在启动过程中底层做了哪些事件,大抵形容如下:
1)基于配置加载类 (通过 ClassLoader 将指定地位的类读到内存 -> 底层通过线程调用 IO 从磁盘读取到内存)。
2) 对类进行剖析 (创立字节码对象 -Class 类型, 通过反射获取器配置信息)。
3) 对于指定配置 (例如由 spring 特定注解形容) 的对象存储其配置信息 (借助 BeanDefinition 对象存储)。
4) 基于 BeanDefinition 对象中 class 的配置构建类的实例(Bean 对象), 并进行 bean 对象的治理(可能会存储到 bean 池)。
SpringBoot 疾速入门剖析
业务形容
在我的项目 Module 中定义一个类,类名为 DefaultCache,而后将此类对象交给 Spring 创立并治理。最初通过单元测试对类的实例进行剖析。
API 设计剖析
基于业务形容,进行 API 及关系设计,如图所示:
代码编写及运行
基于业务及 API 设计,进行代码编写,其过程如下:
第一步:定义 DefaultCache 类
package com.cy.pj.common.cache;
import org.springframework.stereotype.Component;
/**
* @Component 注解形容的类,示意此类交给 Spring 框架治理。*/
@Component
public class DefaultCache {}
第二步:定义 DefaultCacheTests 单元测试类
package com.cy.pj.common.cache;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
@SpringBootTest
public class DefaultCacheTests {
/**
* @Autowired 注解形容的属性由 spring 框架依照肯定规定为其注入值(赋值)* 赋值过程是怎么的?* 1)依赖查找?(请问查找规定是什么?)
* 2)依赖注入?(须要借助什么技术?)
*/ @Autowired
private DefaultCache defaultCache;
@Test
void testDefaultCache(){System.out.println(defaultCache.toString());
//FAQ? defaultCache 变量援用的对象是由谁创立的,存储 到了哪里?bean pool
}
}
第三步:运行单元测试类进行利用剖析
启动运行单元测试办法,检测其输入后果,基于后果剖析:
1)SpringBoot 我的项目中 Bean 对象的构建。
2)SpringBoot 我的项目中 Bean 对象的获取。
运行过程中的 BUG 剖析
- Bean 类型找不到,如图所示:
- 空指针异样(NullPointerExcetpion-NPE), 如图所示:
- 启动类找不到, 如图所示:
- 启动类有多个, 如图所示:
- NoSuchBeanDefinition 异样, 如图所示:
- 单元测试类中的办法增加了参数, 如图所示:
SpringBoot 我的项目中的对象个性剖析
筹备工作
第一步:创立我的项目 Module,例如名字为 05-springboot-features, 如图所示:
第二步:增加业务类 ObjectPool, 代码如下:
package com.cy.pj.common.pool;
@Component
public class ObjectPool{// 假如此对象为一个对象池
public ObjectPool(){// 假如运行我的项目启动类,此构造方法执行了,阐明此类对象构建了。Systemd.out.println("ObjectPool()")
}
}
思考:个别池对象有什么特点?
1)在 JVM 内存会开拓一块绝对比拟大的空间。
2)在这块空间中存储一些对象 (思考基于什么存储构造进行存储 - 数组,链表,散列表)。
3) 基于“享元模式”设计思维,实现内存中对象的可重用性。
第三步: 定义单元测试, 代码如下:
package com.cy.pj.pool;
import com.cy.pj.common.pool.ObjectPool;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class ObjectPoolTests {
@Autowired
private ObjectPool objectPool01;
@Autowired
private ObjectPool objectPool02;
@Test
void testObjectPool01(){System.out.println(objectPool01==objectPool02);
}
}
提早加载
当初思考一个问题, 对于 ObjectPool 这个类,如果我的项目启动当前,临时不会用到这个池对象,是否有必要对其进行创立(默认是会创立的)?咱们晓得没必要,因为占用内存。那如何在启动时不创立此类对象呢?借助 Spring 框架提供的提早加载个性进行实现。例如,咱们能够在须要提早加载的类上应用 @Lazy 注解进行形容,代码如下:
package com.cy.pj.common.pool;
@Lazy
@Component
public class ObjectPool{// 假如此对象为一个对象池
public ObjectPool(){// 假如运行我的项目启动类,此构造方法执行了,阐明此类对象构建了。Systemd.out.println("ObjectPool()")
}
}
此时,咱们再去运行运行启动类,检测 ObjectPool 对象是否创立了,如果没有创立,阐明提早加载失效了。此时,咱们总结一下,什么对象适宜应用提早加载个性呢?大对象,稀少用 (我的项目启动当前,临时用不到) 的对象。
留神:提早加载并不是提早对类进行加载,而是在启动时,临时不创立类的实例。如果想看一下内存中的类是否被加载了,能够通过 JVM 参数进行检测,参数为 -XX:+TraceClassLoading。
对象作用域剖析
在理论的我的项目中内存中的对象有一些可能要重复利用很屡次,有一些可能用完当前再也不必了或者说利用次数很少了。对于常常要重复使用的对象我可思考存储到池中(例如交给 spring 框架进行治理),利用次数很少的对象那就没必要放到池中了,用完当前让它本人销毁就能够了。在 Spring 我的项目工程中为了对这样的对象进行设计和治理,提供了作用域个性的反对,具体利用:
package com.cy.pj.common.pool;
@Scope("singleton")
@Lazy
@Component
public class ObjectPool{// 假如此对象为一个对象池
public ObjectPool(){// 假如运行我的项目启动类,此构造方法执行了,阐明此类对象构建了。Systemd.out.println("ObjectPool()")
}
}
其中,在下面的代码中,咱们应用了 @Scope 注解对类进行形容,用于指定类的实例作用域。不写 @Scope 默认就是单例 (singleton) 作用域,这个作用域会配合提早加载 (@Lazy) 个性应用,示意此类的实例在须要时能够创立一份并且将其存储到 spring 的容器中 (Bean 池), 须要的时候从池中取,以实现对象的可重用。如果一些对象利用次数非常少,能够思考不放入池中,进而应用 @Scope(“prototype”) 作用域对类进行形容, 让此类的对象何时须要何时创立,用完当前,当此对象不可达了,则能够间接被 GC 零碎销毁。
对象生命周期办法
程序中的每个对象都有生命周期,对象创立,初始化,利用,销毁的这个过程称之为对象的生命周期。在对象创立当前要初始化,利用实现当前要销毁时执行的一些办法,咱们能够称之为生命周期办法。但不见得每个对象都会定义生命周期办法。在理论我的项目中往往一些池对象通常会定义这样的一些生命周期办法(例如连接池)。那这样的办法在 spring 工程中如何进行标识呢?通常要借助 @PostConstruct 和 @PreDestroy 注解对特定办法进行形容,例如:
package com.cy.pj.common.pool;
@Scope("singleton")
@Lazy
@Component
public class ObjectPool{// 假如此对象为一个对象池
public ObjectPool(){Systemd.out.println("ObjectPool()")
}
@PostConstruct
public void init(){System.out.println("init()");
}
@PreDestroy
public void destory(){System.out.println("destory()");
}
}
其中:
1)@PostConstruct 注解形容的办法为生命周期初始化办法, 在对象构建当前执行.
2)@PreDestroy 注解形容的办法为生命周期销毁办法, 此办法所在的对象, 如果存储到了 spring 容器, 那这个对象在从 spring 容器移除之前会先执行这个生命周期销毁办法(prototype 作用域对象不执行此办法).
SpringBoot 我的项目中的依赖注入过程剖析
在 SpringBoot 工程中,如果类与类之间存在着肯定的依赖关系,Spring 是如何进行依赖注入的呢,当初咱们就通过一个案例做一个剖析。
筹备工作
第一步:创立一个我的项目 module,如图所示:
第二步:启动运行我的项目,检测是否能胜利启动
案例设计及剖析
为了更好了解 spring 框架的底层注入机制,当初进行案例 API 设计,如图所示:
在这个案例中单元测试类 CacheTests 中定义一个 Cache 接口类型的属性,而后由 Spring 框架实现对 cache 类型属性值的注入。
代码编写及测试剖析
第一步:定义 Cache 接口,代码如下:
package com.cy.pj.common.cache;
public interface Cache {}
第二步:定义 Cache 接口实现类 SoftCache,代码如下:
package com.cy.pj.common.cache;
@Component
public class SoftCache implements Cache{}
第三步:定义 Cache 接口实现类 WeakCache,代码如下:
package com.cy.pj.common.cache;
@Component
public class WeakCache implements Cache{}
第四步:定义 CacheTests 单元测试类,代码如下:
package com.cy.pj.common.cache;
import org.junit.jupiter.api.Test;
@SpringBootTest
public class CacheTests {
@Autowired
@Qualifier("softCache")
private Cache cache;
@Test
public void testCache() {System.out.println(cache);
}
}
其中,@Autowired 由 spring 框架定义,用于形容类中属性或相干办法(例如构造方法)。Spring 框架在我的项目运行时如果发现由他治理的 Bean 对象中有应用 @Autowired 注解形容的属性或办法,能够依照指定规定为属性赋值(DI)。其根本规定是:首先要检测容器中是否有与属性或办法参数类型相匹配的对象,如果有并且只有一个则间接注入。其次,如果检测到有多个,还会依照 @Autowired 形容的属性或办法参数名查找是否有名字匹配的对象,有则间接注入,没有则抛出异样。最初,如果咱们有明确要求,必须要注入类型为指定类型,名字为指定名字的对象还能够应用 @Qualifier 注解对其属性或参数进行形容(此注解必须配合 @Autowired 注解应用)。
第五步:运行 CacheTests 检测输入后果,基于后果了解其注入规定。
编写及测试过程中的 BUG 剖析
- 依赖注入异样,如图所示:
总结(Summary)
本大节为 springboot 技术入门章节,次要讲述了 SpringBoot 工程下,spring 中 bean 对象的编写,个性以及依赖注入的规定,心愿通过这一大节的解说,同学们可能了解咱们为什么要将对象交给 spring 治理,spring 治理对象有什么劣势,咱们在 springboot 工程中应该如何配置这些对象。
springboot
浏览 20.3k 更新于 2020-11-27
举报
赞 222 珍藏 69
分享
本作品系原创,采纳《署名 - 非商业性应用 - 禁止演绎 4.0 国内》许可协定
[
springboot 最佳实际
](https://segmentfault.com/blog…
SpringBoot 技术的势、道、术剖析与实际。
已关注
19 条评论
得票工夫
[](https://segmentfault.com/a/11…
Mario_redamancy:
- @Autowired 注解形容的属性由 spring 框架依照肯定规定为其注入值(赋值), 赋值过程是怎么的?
@Autowired 的赋值过程:
默认优先依照类型去容器中找对应的组件,getBean(Xxx.class), 找到就赋值
如果找到多个雷同类型的组件, 再将属性的名称作为组件的 id 去容器中查找 getBean(“xxx”)
- 什么是依赖?
在 A 类中须要用到 B 类中的办法,通过间接 new 的形式创立 B 类对象,就产生了依赖关系,A 依赖 B - 依赖查找的规定?
1) 依赖拖拽?
依赖拖拽的形式是通过读取配置文件 (.propertis,.xml 等) 获取 bean 信息存入 Map 中,而后查找须要的依赖对象进行创立(就是第二阶段张慎政老师教的 通过配置 <bean> 标签的模式进行对象治理)
2) 上下文查找?
上下文查找不太了解,查了一些材料,上下文查找是与以后环境无关,是动静获取 bean 对象的形式 - 依赖注入?
Spring 会自动识别依赖关系, 由 IOC 容器在运行期间, 动静的将某种依赖关系注入到对象之中 - defaultCache 变量援用由谁创立, 存储到了那里?
defaultCache 变量援用的对象是由 BeanFactory 创立并存储到 bean pool 中, 其中 @Component 代表这个类交给 Spring 进行治理, 默认是单例模式, 所以会存储再 bean 池中
- 咱们为什么要把对象交给 Spring 治理?
1) Spring 治理 Bean 对象能够实现对象对资源的应用
2) 通过 IoC 容器升高对象之间的耦合关系 - 个别池对象有什么特点?
1)在 JVM 内存会开拓一块绝对比拟大的空间。
应用空间换取工夫(频繁的创立和销毁对象会占用大量资源, 所以池化思维就是心愿缩小频繁创建对象所带来的开销)
2)在这块空间中存储一些对象(思考基于什么存储构造进行存储 - 数组,链表,散列表)。
Map + ArrayList
3)基于“享元模式”设计思维,实现内存中对象的可重用性。
通过尽量共享实例来防止 new 出实例
@PreDestroy 注解形容的办法为生命周期销毁办法, 此办法所在的对象, 如果存储到了 spring 容器, 那这个对象在从 spring 容器移除之前会先执行这个生命周期销毁办法 (prototype 作用域对象不执行此办法)
!! 没看到这句话的时候, 我和几个同学激战了将近一个小时,(为什么多例不执行销毁办法, 单例执行的销毁办法又是什么条件销毁的(池子没了? 程序完结?))
最初论断就是因为程序完结了, 要开释资源, 所以容器没了, 导致存在 bean 池中的对象执行销毁办法(单例)
天津核心 08 班