具体的流程图:Spring扫描底层流程 | ProcessOn免费在线作图,在线流程图,在线思维导图 |
AnnotationConfigApplicationContext接口主要做了两件事情:1.scan 2.加载非懒加载的spring a.对象68和70行是java中的JFR机制,相当于查看69行代码执行的黑盒子(耗时,性能等)
b.ClassPathBeanDefinitionScanner接口主要是把扫描到的BeanDefinition注册到spring容器中
c.当有两个类通过component注解的时候,如果内容一致,那么是不会报错的,isCompatible->中newDefinition.getSource().equals(existingDefinition.getSource())会判断资源是不是一致,如果一致直接返回false,这样checkCandidate接口就不会添加新的bean
if (this.checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
this.registerBeanDefinition(definitionHolder, this.registry);
}
d.可以在resources添加spring.components
其中文件内容:com.zhouyu.service.UserService=org.springframeweork.stereotype.Colmponent
e.加载非懒加载的spring
this.refresh()->this.finishBeanFactoryInitialization(beanFactory)->beanFactory.preInstantiateSingletons()
f.SmartInitializingSingleton是在所有的非懒加载的单例Bean创建完成之后执行的代码
g.这样在getBean的时候会调用有参的构造函数,但是因为UserService是一个单例对象,在new AnnotationConfigApplicationConfig的时候就创建了,所以此处还是打印了0.
@Component
public class UserService {
private OrderService orderService;
public UserService() {
System.out.println(0);
}
public UserService(OrderService orderService) {
System.out.println(1);
this.orderService = orderService;
}
public void test() {
System.out.println("test");
}
}
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = (UserService) applicationContext.getBean("userService", new OrderService());
userService.test();
}
}
当前BeanDefinition对应的类成功加载后,就可以实例化对象了,但是...
在Spring中,实例化对象之前,Spring提供了一个扩展点,允许用户来控制是否在某个或某些Bean实例化之前做一些启动动作。这个扩展点叫InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()。比如:
@Component
public class ZhouyuBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class> beanClass, String beanName) throws BeansException {
if ("userService".equals(beanName)) {
System.out.println("实例化前");
}
return null;
}
}
如上代码会导致,在userService这个Bean实例化前,会进行打印。
值得注意的是,postProcessBeforeInstantiation()是有返回值的,如果这么实现:
@Component
public class ZhouyuBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class> beanClass, String beanName) throws BeansException {
if ("userService".equals(beanName)) {
System.out.println("实例化前");
return new UserService();
}
return null;
}
}
userService这个Bean,在实例化前会直接返回一个由我们所定义的UserService对象。如果是这样,表示不需要Spring来实例化了,并且后续的Spring依赖注入也不会进行了,会跳过一些步骤,直接执行初始化后这一步。具体的代码细节在:createBean->resolveBeforeInstantiation中
在这个步骤中就会根据BeanDefinition去创建一个对象了。
扩展:对于任何一个Bean的执行流程如下:
Bean的销毁过程是在spring容器的关闭过程中的。比如:
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = (UserService) context.getBean("userService");
userService.test();
// 容器关闭
context.close();
在Bean创建过程中,在最后(初始化之后),有一个步骤会去判断当前创建的Bean是不是DisposableBean:
在Spring容器关闭过程时:
这里涉及到一个设计模式:适配器模式
在销毁时,Spring会找出实现了DisposableBean接口的Bean。
但是我们在定义一个Bean时,如果这个Bean实现了DisposableBean接口,或者实现了AutoCloseable接口,或者在BeanDefinition中指定了destroyMethodName,那么这个Bean都属于“DisposableBean”,这些Bean在容器关闭时都要调用相应的销毁方法。
所以,这里就需要进行适配,将实现了DisposableBean接口、或者AutoCloseable接口等适配成实现了DisposableBean接口,所以就用到了DisposableBeanAdapter。
会把实现了AutoCloseable接口的类封装成DisposableBeanAdapter,而DisposableBeanAdapter实现了DisposableBean接口。