作者:康话口儿_536 | 来源:互联网 | 2023-09-25 11:19
一、问题描述在项目中,通常都会配置一个或者多个加了@configuration注解的配置类,那么@configuration这个注解到底有神马作用勒?@componentsca
一、问题描述
在项目中,通常都会配置一个或者多个加了@configuration注解的配置类,那么@configuration这个注解到底有神马作用勒?
@componentscan("com")
public class appconfig {
@bean
public testdao testdao() {
return new testdao();
}
}
public class test {
public static void main(string[] args) {
annotationconfigapplicationcontext acc = new annotationconfigapplicationcontext(appconfig.class);
}
}
public class testdao {
public testdao(){
system.out.println("testdao");
}
}
执行上面的代码,我们会发现当我们不加@configuration这个注解的时候我们的testdao 这个类还是还是会被实例化,也会打印testdao。我们的spring环境也可以正常运行。
![](https://img6.php1.cn/3cdc5/982b/525/e76d56cea0fc8dfb.png)
那么我们的@configuration注解是来解决什么问题的勒?
我们来看一下下面这段代码。当我们在appconfig中有2个方法,而且第二个方法调用了第一个方法。
@componentscan("com")
public class appconfig {
@bean
public testdao testdao() {
return new testdao();
}
@bean
public testdao1 testdao1() {
testdao();
return new testdao1();
}
}
public class testdao1 {
public testdao1(){
system.out.println("testdao1");
}
}
不加@configuration的打印结果:
![](https://img6.php1.cn/3cdc5/982b/525/8b9ce7f3d7d847b1.png)
加上@configuration的打印结果:
![](https://img6.php1.cn/3cdc5/982b/525/47b72f93c6f7d1fc.png)
二、分析
从表面来看,当我们不加@configuration注解的时候,我们的testdao会被实例化两次,这违背了我们spring默认单例的设计原则,当加上我们的@configuration注解的时候,testdao只被实例化了一次。
那么其底层到底做了什么,让我们来深追一下spring源码吧。
当我们解析beanappcofig的时候,会给它的一个属性标识为full,表明它是一个全注解类。
![](https://img6.php1.cn/3cdc5/982b/525/a87521a80a482af5.jpeg)
![](https://img6.php1.cn/3cdc5/982b/525/63cd75ee705bd82d.png)
然后在我们调用configurationclasspostprocessor.postprocessbeanfactory()方法的时候会去判断我们的bean工厂当中是否有bean需要进行cglib代理。
![](https://img6.php1.cn/3cdc5/982b/525/10281360d9caf45d.jpeg)
![](https://img6.php1.cn/3cdc5/982b/525/5c445780ef23c882.jpeg)
然后遍历configbeandefs这个map
![](https://img6.php1.cn/3cdc5/982b/525/2c36c65d9a62c51e.jpeg)
![](https://img6.php1.cn/3cdc5/982b/525/43ef1b1a273d7cf4.jpeg)
![](https://img6.php1.cn/3cdc5/982b/525/429c2a547c5b8202.jpeg)
cglib代理主要是对我们的方法进行拦截增强;当我们执行appconfig中的方法的时候会去执行cglib代理类中的代理方法,主要就是callbacks中的方法。
![](https://img6.php1.cn/3cdc5/982b/525/1af24584872be712.png)
![](https://img6.php1.cn/3cdc5/982b/525/1262cc2b3b1b34f0.jpeg)
![](https://img6.php1.cn/3cdc5/982b/525/c373e10313832350.jpeg)
iscurrentlyinvokedfactorymethod(beanmethod))
会判断我们的执行方法和我们的调用方法是否是同一个;如果是同一个就调用父类的方法进行new;如果不是就调用$$beanfactory.getbean()获取。
![](https://img6.php1.cn/3cdc5/982b/525/ee0b9c6de6598e26.jpeg)
三、总结
加上@configuration注解主要是给我们的类加上了cglib代理。
在执行我们的配置类的方法时,会执行cglib代理类中的方法,其中有一个非常重要的判断,当我们的执行方法和我们的调用方法是同一个方法时,会执行父类的方法new(cglib代理基于继承);当执行方法和调用方法不是同一个方法时会调用beanfactory.getbean获取。
![](https://img6.php1.cn/3cdc5/982b/525/fc6d09110431bb67.jpeg)
![](https://img6.php1.cn/3cdc5/982b/525/601bb785909a9d72.jpeg)