Bean的扫描流程
包含过滤器
includeFilters 默认是在 ClassPathBeanDefinitionScanner初始化时,进行扫描 registerDefaultFilters方法。
MetadataReader
类的元数据读取器,主要包含了一个AnnotationMetadata,功能有
- 获取类的名字
- 获取父类的名字
- 获取所实现的所有接口名
- 获取所有内部类的名字
- 判断是不是抽象类
- 判断是不是接口
- 判断是不是一个注解
- 获取拥有某个注解的方法集合
- 获取类上添加的所有注解信息
- 获取类上添加的所有注解类型集合
值得注意的是,CachingMetadataReaderFactory解析某个.class文件得到MetadataReader对象是利用的ASM技术,并没有加载这个类到JVM。并且,最终得到的ScannedGenericBeanDefinition对象,beanClass属性存储的是当前类的名字,而不是class对象。(beanClass属性的类型是Object,它即可以存储类的名字,也可以存储class对象)
最后,上面是说的通过扫描得到BeanDefinition对象,我们还可以通过直接定义BeanDefinition,或解析spring.xml文件的,或者@Bean注解得到BeanDefinition对象。
默认名称的生成
protected String buildDefaultBeanName(BeanDefinition definition) {
String beanClassName = definition.getBeanClassName();
Assert.state(beanClassName != null, "No bean class name set");
String shortClassName = ClassUtils.getShortName(beanClassName);
return Introspector.decapitalize(shortClassName);
}
public static String decapitalize(String name) {
if (name == null || name.length() == 0) {
return name;
}
// 如果首字母和第二个字母都是大写,那么就直接按照原名称作为beanName 否则下面的流程会将首字
if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) && Character.isUpperCase(name.charAt(0))){
return name;
}
char chars[] = name.toCharArray();
chars[0] = Character.toLowerCase(chars[0]);
return new String(chars);
}
Condition的扩展
方便以后使用
单例非懒加载Bean实例化前操作
流程图如下:
合并BeanDefinition
通过扫描得到所有BeanDefinition之后,就可以根据BeanDefinition创建Bean对象了,但是在Spring中支持父子BeanDefinition,和Java父子类类似,但是完全不是一回事。
父子BeanDefinition实际用的比较少,使用是这样的,比如:
<bean id="parent" class="com.zhouyu.service.Parent" scope="prototype"/>
<bean id="child" class="com.zhouyu.service.Child"/>
这么定义的情况下,child是单例Bean。
<bean id="parent" class="com.zhouyu.service.Parent" scope="prototype"/>
<bean id="child" class="com.zhouyu.service.Child" parent="parent"/>
但是这么定义的情况下,child就是原型Bean了。
因为child的父BeanDefinition是parent,所以会继承parent上所定义的scope属性。
而在根据child来生成Bean对象之前,需要进行BeanDefinition的合并,得到完整的child的BeanDefinition。
transformedBeanName方法
这个方法在源码中也是非常常见,主要是做名称的处理转换(针对FactoryBean的),然后对别名的转换功能。
Bean的创建流程
Bean的销毁
在applicationContext里面可以设置bean的销毁,两种方式本质上都是调用doClose方法。
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
applicationContext.close();
//钩子函数 applicationContext.registerShutdownHook();
@Override
public void registerShutdownHook() {
if (this.shutdownHook == null) {
// No shutdown hook registered yet.
this.shutdownHook = new Thread(SHUTDOWN_HOOK_THREAD_NAME) {
@Override public void run() {
synchronized (startupShutdownMonitor) {
doClose();
}
}
};
//jvm线程正常退出时,触发钩子程序。 异常退出不会触发 例如 kill -9
Runtime.getRuntime().addShutdownHook(this.shutdownHook);
}
}
destroyMethodName AutoCloseable DisposableBean DestructionAwareBeanPostProcessor
- 如果当前类实现了DisposableBean或者AutoCloseable接口,则需要在容器销毁时进行bean的销毁。
- 上面不满足,则判断当前的beanDefinition如果设置了destroyMethod(可以通过MergedBeanDefinitionPostProcessor设置),且销毁方法 == (inferred) (带括号); 或者销毁方法为null,但是实现了AutoCloseable接口;
- 再判断是否实现了DisposableBean的接口,没有设置的话,调用close或者shutdown方法。
- 调用DestructionAwareBeanPostProcessor的requiresDestruction(bean)判断是否需要销毁,两个实现类中逻辑如下:
-
- ApplicationListenerDetector中直接使得ApplicationListener是DisposableBean
- InitDestroyAnnotationBeanPostProcessor中使得拥有@PreDestroy注解了的方法就是DisposableBean,并且循环遍历父类
- 把符合上述任意一个条件的Bean适配成DisposableBeanAdapter对象,并存入disposableBeans中(一个LinkedHashMap)
spring容器正常关闭时
- AbstractApplicationContext调用 doClose方法。
- 发布ContextClosedEvent事件。
- 调用lifecycleProcessor的onCloese()方法,去执行stop方法。
- 执行单例bean的销毁方法 --destroyBeans:
-
- 遍历disposableBeans
- 把每个disposableBean从单例池中移除
- 调用disposableBean的destroy();
- 如果这个disposableBean还被其他Bean依赖了,那么也得销毁其他Bean;
- 如果这个disposableBean还包含了inner beans,将这些Bean从单例池中移除掉
- 清空manualSingletonNames,是一个Set,存的是用户手动注册的单例Bean的beanName
- 清空allBeanNamesByType,是一个Map,key是bean类型,value是该类型所有的beanName数组
- 清空singletonBeanNamesByType,和allBeanNamesByType类似,只不过只存了单例Bean
这里涉及到一个设计模式:适配器模式
在销毁时,Spring会找出实现了DisposableBean接口的Bean。
但是我们在定义一个Bean时,如果这个Bean实现了DisposableBean接口,或者实现了AutoCloseable接口,或者在BeanDefinition中指定了destroyMethodName,那么这个Bean都属于“DisposableBean”,这些Bean在容器关闭时都要调用相应的销毁方法。
所以,这里就需要进行适配,将实现了DisposableBean接口、或者AutoCloseable接口等适配成实现了DisposableBean接口,所以就用到了DisposableBeanAdapter。
会把实现了AutoCloseable接口的类封装成DisposableBeanAdapter,而DisposableBeanAdapter实现了DisposableBean接口。