1. bean的生命周期
① 生成bean定义,合并bean定义(父子关系)
② 加载类
③ 实例化前
④ 实例化:Supplier创建对象 || 工厂方法创建对象 || 推断构造方法
⑤ bean定义的后置处理
⑥ 实例化后
⑦ 自动注入
⑧ 处理属性:
⑨ 执行Aware
⑩ 初始化
⑪ 初始化后
2. 扫描bean的底层源码(doScan)
① 扫描配置类中的@ComponentScan包路径,遍历扫描到的资源文件
② 利用ASM技术获取到元数据:
- 根据ExcludeFilter过滤
- 根据IncludeFilter筛选:① 要有@Component注解 ② 如果有@Conditional注解,需要判断是否满足条件(SpringBoot 用的比较多)。
③ 构造bean定义,属性赋值:比如metaData(类的元数据)、beanClass(这里是类的全限定名,后面创建bean用这个加载)
④ 进一步筛选:过滤非静态内部类、接口类、没有@LookUp修饰方法的抽象类
①->④属于findCandidateComponents(basePackage);的过程
⑤ 遍历筛选后的bean定义,属性赋值:setScope、setBeanName、解析@Lazy、@Primary、@DependsOn、@Role、@Description
⑥ 检查Spring容器中是否存在这个beanName,不存在,注册Bean定义,存在抛异常:重复的beanName
3. @LookUp注解其它用法
@Component
Class UserService{
@Autowired
private User user;
void test(){
system.out.println(user);
}
}
@Component
@Scope("prototype")
public class User{
}
// 测试...
UserService userService = (UserService) context.getBean("userService");
userService.test();
userService.test();
userService.test();
// 测试结果:都是打印同一个user对象,因为UserService 是单例的,user属性只会注入一次不
@Component
Class UserService{
@Autowired
private User user;
void test(){
system.out.println(findUser());
}
@Lookup("user")
public User findUser(){
return null;
}
}
// 添加@Lookup修饰的方法,那么就会打印不同的user
4. 创建非懒加载的单例bean:finishBeanFactoryInitialization(beanFactory)
① 遍历beanNames,合并bean定义(如果有父子关系的bean定义),缓存到mergedBean定义Map
② 根据bean定义属性值,判断不是抽象的是单例并且不是懒加载
1. 不是抽象的:不是指抽象类,因为抽象类就不会创建bean定义,这里指bean定义不是抽象的,基于xml配置bean设置抽象的bean定义,即abstract = true
2. 抽象的bean定义有什么用:自己不能创建bean,但是可以供子类继承,创建子类。子类继承,会继承父类的bean属性,即合并bean定义,生成新的RootBeanDefinition
③ 判断是否FactoryBean
- 是,先创建普通的bean。判断如果实现的是SmartFactoryBean,重写isEagerInit()方法可以做到Spring启动的时候就调用getObject()提前创建好真正的bean,缓存到factoryBeanMap中
如果实现的不是SmartFactoryBean,在getBean()的时候才会创建调用getObject()方法创建真正的bean返回
- 否,创建普通的bean
④ 以上完成非懒加载的bean全部创建,然后遍历bean,判断是否实现SmartInitializingSingleton。如果是,这里就会调用aferSingletonsInstantiated()方法
5.doGetBean底层源码:
① 根据beanName,从单例池中找,没有找到则开始创建
② 获取bean定义,判断dependsOn属性值,如果不为空,将被依赖关系注册到dependentBeanMap中,然后会先创建@DependsOn注解依赖的bean
③ 判断是单例,还是原型,还是其它Scope,然后创建bean
1. 创建单例bean,涉及到单例池。从单例池中获取,获取不到执行传入的lambda表达式创建bean,创建完再放到单例池中,关键代码如下
2. 创建原型bean,就直接创建
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
6.创建bean底层源码:
① 如果bean对应的类,还没有加载,需要完成类加载
② 获取后置处理器,判断如果不为空,遍历执行实例化前的回调方法。比如执行实例化前的回调方法,自己创建bean返回,而不是由Spring创建bean。
但是还会经过初始化后,为了兼容AOP
③ 如果没有后置处理器干预bean的创建,Spring开始实例化bean(doCreateBean)
④ 推断构造方法,实例化bean。获取后置处理器,执行修改bean定义的回调方法。这里就是执行@Autowired、@Resource的后置处理器,解析注入点缓存起来
程序可以在这里添加后置处理器,干预bean实例化后的逻辑,比如通过给bean定义设置初始化方法、属性填充等操作
⑤ 属性填充:
- 获取后置处理器,判断如果不为空,遍历执行实例化后的回调方法
- 处理Spring自带的注解属性autowire,比如@Bean(autowire=Autowire.BY_NAME)
- 判断bean类中的所有属性,有对应的set方法,且不是基本类型,才会处理
- BY_NAME,根据set方法后面的名字作为beanName,从容器中找对象,进行属性赋值
- BY_TYPE,根据set方法的参数类型,从容器中找对象,进行属性赋值
- 执行后置处理器,属性填充的回调方法。这里就是执行@Autowired、@Value、@Resource的后置处理器,进行属性填充
- @Autowired属性填充的过程:所有被@Autowired修饰的属性和方法都是注入点,在前面步骤已经被提前解析
- 注解在字段上,先根据字段类型找bean
- 注解在方法上:如果是无参的,直接利用反射调用方法。如果是有参的,参数值先根据类型找bean,利用反射执行该方法
- 如果字段或者方法参数根据类型找到多个bean:
- 如果使用了@Primary、@Priority(''数字')、@Qualifer("名字")修饰,会直接取优先级最高的bean
- 如果没有使用以上注解,再根据bean的名字找bean,最终没有找到会报错
- 如果属性或方法参数使用@Lazy注解修饰,注入的是代理对象,只有到真正使用对象调用方法时,执行代理逻辑去容器中找这个bean,然后通过bean调用该方法
- @Resource属性填充的过程:所有被@Autowired修饰的属性和方法都是注入点,在前面步骤已经被提前解析
- 是否指定bean的名字和bean的类型,没有指定使用默认的
- 使用@Lazy注解修饰,直接注入代理对象
- 先根据bean的名字找,找不到再根据类型找
- Java级别的,Spring做了支持。如果不使用Spring框架,就要使用@Resource
- @Autowired属性填充的过程:所有被@Autowired修饰的属性和方法都是注入点,在前面步骤已经被提前解析
⑥ 初始化
- 判断bean是否实现Aware接口,执行回调方法,比如BeanNameWare setBeanName()、ApplicationContextWare setApplicationContext() 回传需要的对象
- 获取后置处理器,遍历执行初始化前的回调方法。Spring添加了处理@PostConstruct的后置处理器
- 获取后置处理器,遍历执行初始化后的回调方法。如果开启AOP,这里就是执行AOP的后置处理器,判断是否需要创建代理对象
⑦ 寻找bean销毁方法,缓存起来。在Spring容器关闭时,会执行bean销毁的方法
- springmvc、springboot底层就是向JVM进程注册一个关闭钩子,当进程正常关闭的时候会触发bean销毁的方法,强制关闭进程是不会执行的
- 实现bean销毁:
- 实现接口
- 使用@PreDestroy修饰方法