spring-创建Bean源码分析
1.找到创建bean的入口
按照以下几个步骤找到preInstantiateSingletons()方法,创建bean就是在这个方法中。
1.进入AnnotationConfigApplicationContext的AnnotationConfigApplicationContext(Class<?>... componentClasses)方法
2.进入refresh()方法中找到这个方法:finishBeanFactoryInitialization(beanFactory);
3.进入finishBeanFactoryInitialization(beanFactory)方法中找到这个方法:beanFactory.preInstantiateSingletons();
4.进入到 preInstantiateSingletons()方法
2.创建bean
接下来就主要分析这个方法preInstantiateSingletons();
1.拿到beanName的集合
beanDefinition在注册的时候会将beanDefinitionName存到beanDefinitionNames集合中。所以这里就直接使用beanDefinitionNames拿到beanName的集合,然后循环遍历
2.合并bean
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
根据bean的名字通过这个方法(getMergedLocalBeanDefinition(beanName))得到一个新的RootBeanDefinition.
先是创建了两个RootBeanDefinition 类型的对象,mbd 和 previous 接着判断了containingBd == null,这个判断在这个流程中肯定是 true ,因为传进来的就null。 所以基本都会走到这个判断里面,根据beanName从mergedBeanDefinitions中获取,然后给mbd赋值 接着会做一个判断,如果mbd有值,那么直接就返回。 然后会先将mbd 赋值给previous, 判断传进来bd(beanDefinition)有没有父beanDefinition。 如果有父beanDefinition那么就会先处理父beanDefinition,这里是递归调用的
处理完父beanDefinition之后,就会转换为RootBeanDefinition并赋值。
mbd = new RootBeanDefinition(pbd); //转换
mbd.overrideFrom(bd);//赋值
如果没有父beanDefinition,那么就会直接转换为RootBeanDefinition。 最后会放到mergedBeanDefinitions中。
if (containingBd == null && isCacheBeanMetadata()) {
this.mergedBeanDefinitions.put(beanName, mbd);
}
注意:这里的转换为RootBeanDefinition都是重新生成的,不会在原有的BeanDefinition上修改。
3.FactoryBean
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
- !bd.isAbstract(): 不能是抽象的beanDefinition(这里指的不是抽象类)\
- bd.isSingleton(): 必须是单例的\
- !bd.isLazyInit():不能是懒加载的 只有符合上述条件才可以 然后会根据beanName判断是不是FactoryBean,如果是FactoryBean那么就进入了FactoryBean的创建过程。 先拼接&+beanName作为参数调用getBean(),这时候获取的bean是带有&的bean. 然后再判断是不是实现了FactoryBean接口,如果是会继续判断是不是实现了SmartFactoryBean接口(安全管理器先不考虑) 这个接口相比较FactoryBean接口可以指定isEagerInit的值(默认是false),如果是true,这时候会去调用getObject()方法,如果不是true ,会在这个时候:context.getBean("person");调用。
在调用getBean()方法的时候,无论是FactoryBean还是非FactoryBean(普通Bean)的创建都是在这个方法里面。 FactoryBean在创建的时候会先创建带&的bean.然后存到单例池(存入键不带&,在getBean方法中有对&的处理)。 接着会经过一系列的判断,先去factoryBeanObjectCache缓存中去取,如果没有然后在调用getObject()获取,并存入到factoryBeanObjectCache缓存中。
String beanName = transformedBeanName(name);
这行代码会对 &beanName 做处理
如果getCachedObjectForFactoryBean没有拿到,就会执行
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
调用getObject()方法返回对象。
4.getBean(beanName)
1. 处理beanName;
String beanName = transformedBeanName(name);
这个beanName会有这么几种情况:
1.FactoryBean: 会加&,例如:
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
context.getBean("&lynnFactoryBean");
2.bean 有别名
例如:
@ComponentScan(value = "com.xl.service")
public class AppConfig {
@Bean({"person","person1","person2"})
public Person person(){
return new Person();
}
}
person 是bean的名字,person1才是bean名字,如果只有peson ,那么这个bean 是没有别名的。
spring存储别名是以这种方式存储的:
获取bean
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
context.getBean("person1");
2.从单例池获取,并判断
这个判断里面的逻辑在FactoryBean中已经分析过了,这里就不说了。
3.父beanFactory
BeanFactory parentBeanFactory = getParentBeanFactory();
先去父beanFactory获取,如果拿到就直接返回。正常情况下parentBeanFactory 肯定是空的。
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
//context.getBean("&lynnFactoryBean");
System.out.println(context.getBean("person"));
}
}
指定父BeanFactory
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext per = new AnnotationConfigApplicationContext(AppConfigTest.class);
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(AppConfig.class);
context.setParent(per);
context.refresh();
//context.getBean("&lynnFactoryBean");
System.out.println(context.getBean("person"));
}
}
4.获取合并后的beanDefinition,并判断
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
获取合并后的beanDefinition,然后去判断beanDefinition是否是抽象的beanDefinition,如果是抽象的直接报错。
5.处理dependsOn注解。
@Component
@DependsOn("company")
public class Person {
}
创建person的时候,检测到person依赖company,那么就会先创建company:
getBean(dep);
dep就是company,这样就又会到doGetBean方法。 注意:如果DependsOn注解引起的循环依赖是没办法解决的,直接报异常:
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
6.创建不同类型的bean
1.创建单例bean
getSingleton() 中的lambda表达式返回的就是一个对象。先去单例池拿,拿不到用lambda表达式返回的bean. 然后还会执行
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
以防止是FactoryBean.
2.创建原型bean
原型bean就是直接使用createBean 创建,before是先标记,after是去除标记。
3.创建其他类型的bean
这个地方就和springMvc有关了
7.createBean
无论是什么类的bean,都是要先去创建bean的,所以createBean就比较重要了。
1. 获取beanClass
获取类加载器,并通过类加载器以及全类名获取beanClass
上图蓝框部分是某种情况下会执行。正常逻辑是执行
mbd.resolveBeanClass(beanClassLoader)
getBeanClassName() 获取的值是在扫描的时候就已经赋值了,不过是String类型。
2.实例化前
InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation
执行示例化前这个方法,有返回对象,会直接返回对象。 通过一个示例来看下: 先实现这个接口覆盖实例化前的方法
@Component
public class LynnPostProcessor implements InstantiationAwareBeanPostProcessor {
//初始化前
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if(beanName.equals("person")){
System.out.println(" before "+bean);
}
return bean;
}
//初始化后
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if(beanName.equals("person")){
System.out.println("after hou: "+bean);
}
return bean;
}
//实例化前
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if(beanName.equals("person")){
return new Person();
}
return null;
}
}
@Component
public class Company {
@Autowired
private User user;
}
@Component
public class Person {
@Autowired
private Company company;
}
@Component
public class User {
public void test(){
System.out.println("123123123");
}
}
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
Company company = context.getBean("company", Company.class);
User user = context.getBean("user", User.class);
Person person = context.getBean("person", Person.class);
}
}
Company,User,Person
company 和 person 是有属性的。
在实例化前对person进行处理: 创建一个person返回。
compay是没有做处理的。
执行后的结果: company的属性是有值的,person的属性是没值的。
将实例化前对person处理的逻辑去掉,可以看到又有属性了。 所以,实例化前如果有返回对象,后续就不会执行spring创建bean的逻辑了。 接下来详细看下是怎么实现的:
hasInstantiationAwareBeanPostProcessors()
上图这个方法是将所有beanPostProcessor分类缓存起来,以方便后续调用。
再看下图这个方法的
上图这里就是调用实例化前的地方,这个地方加循环是因为:会有很多地方实现这个接口,只要有一个实现有对象返回后续的就都不执行了。
3.实例化
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
这个就是创建bean实例,这里会处理@Bean注解,以及使用推断构造方法创建实例
4.处理已经合并过的BeanDefinition
MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition()
可以这样使用
这个地方是可以 修改beanDefinition的部分属性,作为扩展点。
5.处理循环依赖
6.实例化后
InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation()
7.属性填充
下图是不使用@Autowired就能进行属性填充,
如下图这样使用
InstantiationAwareBeanPostProcessor.postProcessProperties()
这里是对带有@Autowired的属性进行填充
8.回调Aware
9.初始化前
10.初始化
11.初始化后
12.销毁
用法:
销毁逻辑: 1.容器关闭的时候销毁。 2. 会先去判断bean有没有销毁逻辑 3. 如果有销毁逻辑会存到disposableBeans Map . 4. 当容器关闭时,会循环这个map缓存执行销毁逻辑,同时会将大部分缓存清空:单例池等。
转载自:https://juejin.cn/post/7153445932892651534