SpringBoot 启动过程中底层做了哪些?
- 基于配置加载类,将类(启动类所蕴含的:JVM 根底类库优先,spring 外部类库 … 可通过栈追踪 -XX:TraceClassLoading 对 JVM 参数剖析)读到内存。
- 对具备注解、配置文件特定配置的对象进行存储配置信息(借助 BeanDefinition 存储)
- 基于 BeanDefinition 对象中的 class 的配置构建类的实例 Bean 对象,并进行 Bean 对象治理(有些可能存储到 bean 池中)。
业务形容
在我的项目 Module 中定义一个类,类名为 DefaultCache,而后将此类对象交给 Spring 创立并治理。最初通过单元测试对类的实例进行剖析。
API 设计剖析
基于业务形容,进行 API 及关系设计,如图所示:
基于业务及 API 设计,进行代码编写,其过程如下:
1:
package com.cy.pj.common.cache;
import org.springframework.stereotype.Component;
@Component
// 用来形容由 spring 治理的个别(common)组件
public class DefaultCache {
}
2:
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
// 此注解形容的类为 springboot 工程中的单元测试类
public class DefaultCacheTests {
//has a
@Autowired
// 此注解用于通知 spring 请按指定规定为此属性赋值
private DefaultCache defaultCache;
@Test
public void testDefaultCache(){
System.out.println("测试:");
System.out.println(defaultCache.toString());
}
}
SpringBoot 我的项目中的对象个性剖析
1:
package com.cy.pj.common.pool;
import org.springframework.stereotype.Component;
@Component
public class ObjectPool {
public ObjectPool(){// 通常利用构造方法来检测该类有没有创立
System.out.println(“ObjectPool 类创立了!”);
}
}
2:
package com.cy.pj.common.pool;
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 testObjectPool(){
System.out.println("测试:");
System.out.println(objectPool01==objectPool02);
/**
- 若为 true,则表明为同一对象,即没有创立新对象
- 阐明了 BeanPool 中有且只有一个对象 ObjectPool
*/
提早加载
当初思考一个问题, 对于 ObjectPool 这个类,如果我的项目启动当前,临时不会用到这个池对象,是否有必要对其进行创立(默认是会创立的)?咱们晓得没必要,因为占用内存。那如何在启动时不创立此类对象呢?借助 Spring 框架提供的提早加载个性进行实现。例如,咱们能够在须要提早加载的类上应用 @Lazy 注解进行形容,代码如下:
package com.cy.pj.common.pool;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
@Lazy
@Component
public class ObjectPool {
public ObjectPool(){// 通常利用构造方法来检测该类有没有创立
System.out.println(“ObjectPool 类创立了!”);
}
}
对象作用域剖析
在理论的我的项目中内存中的对象有一些可能要重复利用很屡次,有一些可能用完当前再也不必了或者说利用次数很少了。对于常常要重复使用的对象我可思考存储到池中(例如交给 spring 框架进行治理),利用次数很少的对象那就没必要放到池中了,用完当前让它本人销毁就能够了。在 Spring 我的项目工程中为了对这样的对象进行设计和治理,提供了作用域个性的反对,具体利用:
package com.cy.pj.common.pool;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Scope(“singleton”)
@Lazy
@Component
public class ObjectPool {
public ObjectPool(){// 通常利用构造方法来检测该类有没有创立
System.out.println(“ObjectPool 类创立了!”);
}
}
其中,在下面的代码中,咱们应用了 @Scope 注解对类进行形容,用于指定类的实例作用域。不写 @Scope 默认就是单例 (singleton) 作用域,这个作用域会配合提早加载 (@Lazy) 个性应用,示意此类的实例在须要时能够创立一份并且将其存储到 spring 的容器中 (Bean 池), 须要的时候从池中取,以实现对象的可重用。如果一些对象利用次数非常少,能够思考不放入池中,进而应用 @Scope(“prototype”) 作用域对类进行形容, 让此类的对象何时须要何时创立,用完当前,当此对象不可达了,没有援用对象时,则能够间接被 GC 零碎销毁。
对象生命周期办法
程序中的每个对象都有生命周期,对象创立,初始化,利用,销毁的这个过程称之为对象的生命周期。在对象创立当前要初始化,利用实现当前要销毁时执行的一些办法,咱们能够称之为生命周期办法。但不见得每个对象都会定义生命周期办法。在理论我的项目中往往一些池对象通常会定义这样的一些生命周期办法(例如连接池)。那这样的办法在 spring 工程中如何进行标识呢?通常要借助 @PostConstruct 和 @PreDestroy 注解对特定办法进行形容,例如:
package com.cy.pj.common.pool;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Scope(“singleton”)
@Lazy
@Component
public class ObjectPool {
public ObjectPool(){// 通常利用构造方法来检测该类有没有创立
System.out.println(“ObjectPool 类创立了!”);
}
@PostConstruct
// 该注解形容的办法为生命周期初始化办法,在构建办法前执行
public void init(){
System.out.println("init()");
}
@PreDestroy
/**
- 该注解形容的办法为生命周期销毁办法,此办法所在的对象
- 若存储到 spring 容器中,则在销毁容器前,先执行该办法
- prototype 作用域对象不执行该办法
*/
public void destroy(){
System.out.println("destroy()");
}
}
SpringBoot 我的项目中的依赖注入过程剖析
在 SpringBoot 工程中,如果类与类之间存在着肯定的依赖关系,Spring 是如何进行依赖注入的呢,当初咱们就通过一个案例做一个剖析。
案例设计及剖析
为了更好了解 spring 框架的底层注入机制,当初进行案例 API 设计,如图所示:
代码编写及测试剖析
第一步:定义 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;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class CacheTests {
@Autowired
//@Qualifier("")
/**
* 此处必须指定实现类的类型
* 即实现 Cache 有两个类,SoftCache 和 WeakCache
* 但不指定类型时,底层不晓得找哪一个,就会报错
* 能够通过 @Qualifier("softCache")来指定类型
* 也可通过 Cache softCache 让其比拟参数自行查找
* 该参数是底层创立并 命名的,默认类名(首字母小写)*/
private Cache softCache;
@Test
void testCache(){System.out.println("测试:");
System.out.println(softCache);
}
}
其中,@Autowired 由 spring 框架定义,用于形容类中属性或相干办法(例如构造方法)。Spring 框架在我的项目运行时如果发现由他治理的 Bean 对象中有应用 @Autowired 注解形容的属性或办法,能够依照指定规定为属性赋值(DI)。其根本规定是:首先要检测容器中是否有与属性或办法参数类型相匹配的对象,如果有并且只有一个则间接注入。其次,如果检测到有多个,还会依照 @Autowired 形容的属性或办法参数名查找是否有名字匹配的对象,有则间接注入,没有则抛出异样。最初,如果咱们有明确要求,必须要注入类型为指定类型,名字为指定名字的对象还能够应用 @Qualifier 注解对其属性或参数进行形容(此注解必须配合 @Autowired 注解应用)。
第五步:运行 CacheTests 检测输入后果,基于后果了解其注入规定。