前言
上篇博客基本梳理了一下@Configuration註解的類註冊源碼上的一些細節和流程。
一個實例
準備三個類,一個配置類,兩個普通類,其中一個普通類可以什麼都不做
@Component
public class TestBean {
//這個普通類裏面只有一個構造方法
public TestBean() {
System.out.println("this is testBean one constructor method");
}
}
/**
* autor:liman
* createtime:2020/4/6
* comment:
*/
public class TestBean02 {
}
配置類
@Configuration
@ComponentScan(value="com.learn.importselector.config")
public class AppConfig {
@Bean
public TestBean testBean(){
return new TestBean();
}
@Bean
public TestBean02 testBean02(){
testBean();//這裏也會調用testBean方法。
return new TestBean02();
}
}
問題:TestBean的構造方法會被調用幾次?注意在TestBean02中也會調用testBean方法。
引入一個測試代碼
public class TestOutOfConfig {
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext
= new AnnotationConfigApplicationContext(AppConfig.class);
TestBean02 testBean = annotationConfigApplicationContext.getBean(TestBean02.class);
}
}
答案:如果加上了@Configuration,則只會調用一次,如果去掉@Configuration註解則會調用兩次
運行情況:
加入了@Configuration註解後的運行情況
取消@Configuration註解後的運行情況
問題:@Configuration到底幹了啥?爲啥去掉@Configuration之後會調用兩次?
CGLIB代理的簡單實例
其實之前總結過代理,這裏還是想說一下CGLIB的代理,因爲後面的源碼閱讀會用到
一個目標類
/**
* autor:liman
* createtime:2020/4/11
* comment:
*/
public class HelloService {
public HelloService(){
System.out.println("this is construct method of HelloService");
}
//這個方法不會被代理,因爲是final方法
final public String sayOthers(String name){
System.out.println("hello service to others : "+name);
return null;
}
public void sayHello(){
System.out.println("helloService:sayHello");
}
}
一個方法調用攔截器
public class SelfMethodInterceptor implements MethodInterceptor {
/**
*
* @param o 目標對象
* @param method 目標方法
* @param objects 目標方法參數
* @param methodProxy 目標方法的代理類 methodProxy.invokeSuper()
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("self interceptor before");
System.out.println(method.getName());//sayHello()
methodProxy.invokeSuper(o,objects);
System.out.println(methodProxy.getClass().getSimpleName());
System.out.println(methodProxy.getSignature());//代理後的方法
System.out.println("self interceptor after");
return null;
}
}
調用的實例
/**
* autor:liman
* createtime:2020/4/11
* comment:這裏需要引入CGLIB的調用包
*/
public class CglibTest {
public static void main(String[] args) {
//將生成的代理類導入到指定文件夾,可以查看CGLIB生成的代理類的class源碼
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"E:\\cglib_class");
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(HelloService.class);
enhancer.setCallback(new SelfMethodInterceptor());
HelloService proxy = (HelloService) enhancer.create();
proxy.sayHello();
}
}
依舊是個前提
我們這篇博客是要總結@Configuration這個註解spring底層到底幹了什麼,這裏我們就從上篇博客的後續開始,還是貼入我們討論了很多次的方法
//TODO :PostProcessorRegistrationDelegate中的第56行
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
//TODO: 定義一個容器,表示已經處理過了的BeanFactoryPostProcessor
Set<String> processedBeans = new HashSet<>();
//TODO:如果BeanFactory是一個註冊器(這個好像必會進入)
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
//TODO:這裏定義了兩個集合,一個是BeanFactoryPostProcessor,一個是BeanDefinitionRegistryPostProcessor
//TODO:放自定義的BeanFactoryPostProcessor
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
//TODO:BeanDefinitionRegistryPostProcessor只是繼承了BeanFactoryPostProcessor接口而已
//TODO:放自定義的BeanDefinitionRegistryPostProcessor
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
//TODO : 遍歷傳入過來的集合beanFactoryPostProcessors
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
//TODO:如果自定義的BeanFactoryPostProcessor實現了BeanDefinitionRegistryPostProcessor接口
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {//TODO:如果是BeanDefinitionRegistryPostProcessor
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);//TODO:調用postProcessor其中的方法
registryProcessors.add(registryProcessor);
}
else {//TODO:如果自定義的BeanFactoryPostProcessor沒有實現現BeanDefinitionRegistryPostProcessor接口
regularPostProcessors.add(postProcessor); //TODO:將自定義的BeanFactoryProcessor放到上面定義的集合中
}
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
// Separate between BeanDefinitionRegistryPostProcessors that implement
// PriorityOrdered, Ordered, and the rest.
//TODO:又定義一個集合存放BeanDefinitionRegistryPostProcessor,這個集合存放的是spring內部實現了這個接口的類
//TODO:放spring內部定義的BeanDefinitionRegistryPostProcessor
//TODO:每次真正調用的,纔是這個集合中的BeanDefinitionRegistryPostProcessor
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
//TODO:根據bean的類型獲取bean的名稱,這裏獲取的是BeanDefinitionRegistryPostProcessor類型的
//TODO:首先調用實現了PriorityOrdered接口的BeanDefinitionRegistryPostProcessor
//TODO:根據Type獲取對應類型的beanName,這裏纔會獲取出內部定義的ConfigurationClassPostProcessor
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
//TODO:遍歷上面獲得的postProcessorNames,並根據每個beanName獲取對應的beanDefinition,然後放到currentRegistryProcessors中
//TODO:如果沒有自定義的,則這個時候這裏就一個
//TODO:同時將遍歷的每一個beanName放到processedBeans中
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
//TODO:將 ConfigurationClassPostProcessor 標記爲已經處理
processedBeans.add(ppName);
}
}
//TODO:設置排序,不重要
sortPostProcessors(currentRegistryProcessors, beanFactory);
//TODO:合併兩個集合,將spring自定義的Processors加入到registryProcessors中,可以看到所謂的currentRegistryProcessors就是一個過渡的
registryProcessors.addAll(currentRegistryProcessors);
//TODO:真正的開始調用BeanDefinitionRegistryPostProcessor中的方法
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
//TODO:清空currentRegistryProcessors,這裏就清除了 ConfigurationClassPostProcessor
currentRegistryProcessors.clear();
// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
//TODO:開始調用實現了Ordered接口的BeanDefinitionRegistryPostProcessor類
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
//TODO:和上面的操作一樣,但是這個時候 currentRegistryProcessors 中只會有實現了Ordered接口的BeanDefinitionRegistryPostProcessor
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
//TODO:最後,調用其他的BeanDefinitionRegistryPostProcessors,直到沒有更多的BeanDefinitionRegistryPostProcessors實現類
//TODO:簡單點說這裏就是在掃除剩餘的沒被調用的BeanDefinitionRegistryPostProcessors實例
boolean reiterate = true;
while (reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
}
// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
//TODO:到這裏,調用postProcessBeanFactory(即BeanDefinitionRegistryPostProcessors的父類)的回調方法,這裏面就有針對@Configuration類的增強操作
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}
//TODO:如果一個beanFactory不是註冊器,這個應該是一個兼容操作,老版本的spring的BeanFactory是沒有實現Registry接口的
else {
// Invoke factory processors registered with the context instance.
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
//TODO:開始處理 BeanFactoryProcessor 類型的類,並回調指定的方法(就是隻實現了BeanFactoryPorcessor接口的類)
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
//TODO:如果已經在processedBeans集合中,這裏不再做處理
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();//TODO:存放實現了 PriorityOrdered 接口的 BeanFactoryProcessor
List<String> orderedPostProcessorNames = new ArrayList<>(); //TODO:存放實現了 Ordered 接口的 BeanFactoryProcessor
List<String> nonOrderedPostProcessorNames = new ArrayList<>();//TODO:存放沒有實現 Ordered 接口也沒有實現 PriorityOrdered 的 BeanFactoryProcessor
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) {
// skip - already processed in first phase above
}
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
//TODO:調用實現了PriorityOrdered接口的BeanFactoryPostProcessor回調方法
// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
//TODO:調用實現了Ordered接口的 BeanFactoryPostProcessors 回調方法
// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
// Finally, invoke all other BeanFactoryPostProcessors.
//TODO:最後,處理兩個接口爲沒有實現的正常的 BeanFactoryPostProcessors 回調方法
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
// Clear cached merged bean definitions since the post-processors might have
// modified the original metadata, e.g. replacing placeholders in values...
beanFactory.clearMetadataCache();
}
這裏再次總結一下spring中回調BeanFactoryPostProcessor接口實現類的方法,就是上面這段代碼,invokeBeanFactoryPostProcessors方法。
這個方法在AbstractApplicationContext類中被調用的時候,傳入進來的是這樣的
//TODO:通過委託對象調用指定的BeanFactoryPostProcessor(這裏是調用自定義的BeanFactoryPostProcessor)
//TODO:這裏的getBeanFactoryPostProcessors()並不是取出spring內部定義的BeanFactoryPostProcessor,而是取出程序員自己定義的BeanFactoryPostProcessor
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
這裏只需記住一點,通過getBeanFactoryPostProcessors()
得到的是我們自己定義的BeanFactoryPostProcessor 。前面我們說過,BeanFactoryPostProcessor
其實還有一個子接口BeanDefinitionRegistryPostProcessor
源碼如下所示
/**
* Extension to the standard {@link BeanFactoryPostProcessor} SPI, allowing for
* the registration of further bean definitions <i>before</i> regular
* BeanFactoryPostProcessor detection kicks in. In particular,
* BeanDefinitionRegistryPostProcessor may register further bean definitions
* which in turn define BeanFactoryPostProcessor instances.
*
* @author Juergen Hoeller
* @since 3.0.1
* @see org.springframework.context.annotation.ConfigurationClassPostProcessor
*/
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
/**
* Modify the application context's internal bean definition registry after its
* standard initialization. All regular bean definitions will have been loaded,
* but no beans will have been instantiated yet. This allows for adding further
* bean definitions before the next post-processing phase kicks in.
* @param registry the bean definition registry used by the application context
* @throws org.springframework.beans.BeansException in case of errors
*/
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}
接口BeanDefinitionRegistryPostProcessor
在BeanFactoryPostProcessor
的基礎上擴展了一個方法。這也就意味着BeanDefinitionRegistryPostProcessor
接口有兩個方法。我們看看spring是怎麼處理的(其實關於spring如何調用BeanFactoryPostProcessor
後置處理的,在上面整個方法的代碼中,已經通過註解給出了)。下面一段段解構上述方法。首先說明一下,在invokeBeanFactoryPostProcessors方法中,spring爲了兼容原來老版本的操作,做了一個if判斷,判斷如果BeanFactory是BeanDefinitionRegistry的話就進入一個if語句塊,如果不是,就走else分支。這裏我們從if語句塊開始。
1、先處理自定義的BeanFactoryPostProcessor
//TODO:如果BeanFactory是一個註冊器(這個好像必會進入)
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
//TODO:這裏定義了兩個集合,一個是BeanFactoryPostProcessor,一個是BeanDefinitionRegistryPostProcessor
//TODO:放自定義的BeanFactoryPostProcessor
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
//TODO:BeanDefinitionRegistryPostProcessor只是繼承了BeanFactoryPostProcessor接口而已
//TODO:放自定義的BeanDefinitionRegistryPostProcessor
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
//TODO : 遍歷傳入過來的集合beanFactoryPostProcessors
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
//TODO:如果自定義的BeanFactoryPostProcessor實現了BeanDefinitionRegistryPostProcessor接口
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {//TODO:如果是BeanDefinitionRegistryPostProcessor
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);//TODO:調用postProcessor其中的方法
registryProcessors.add(registryProcessor);
}
else {//TODO:如果自定義的BeanFactoryPostProcessor沒有實現現BeanDefinitionRegistryPostProcessor接口
regularPostProcessors.add(postProcessor); //TODO:將自定義的BeanFactoryProcessor放到上面定義的集合中
}
}
//............暫時省略後面的代碼
}
我們說過,通過參數傳遞進來的beanFactoryPostProcessors
是我們自己定義的beanFactoryPostProcessors,可以很明顯的看到,如果我們定義的beanFactoryPostProcessors實現了BeanDefinitionRegistryPostProcessor接口,則會被先處理,然後放入registryProcessors集合中,如果只實現了BeanFactoryPostProcessor接口,則會放入regularPostProcessors集合中。
2、開始處理spring內部實現了BeanDefinitionRegistryPostProcessor接口的實現類。
之後我們接着往下看
// Separate between BeanDefinitionRegistryPostProcessors that implement
// PriorityOrdered, Ordered, and the rest.
//TODO:又定義一個集合存放BeanDefinitionRegistryPostProcessor,這個集合存放的是spring內部實現了這個接口的類
//TODO:放spring內部定義的BeanDefinitionRegistryPostProcessor
//TODO:每次真正調用的,纔是這個集合中的BeanDefinitionRegistryPostProcessor
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
//TODO:根據bean的類型獲取bean的名稱,這裏獲取的是BeanDefinitionRegistryPostProcessor類型的
//TODO:首先調用實現了PriorityOrdered接口的BeanDefinitionRegistryPostProcessor
//TODO:根據Type獲取對應類型的beanName,這裏纔會獲取出內部定義的ConfigurationClassPostProcessor
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
//TODO:遍歷上面獲得的postProcessorNames,並根據每個beanName獲取對應的beanDefinition,然後放到currentRegistryProcessors中
//TODO:如果沒有自定義的,則這個時候這裏就一個
//TODO:同時將遍歷的每一個beanName放到processedBeans中
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
//TODO:將 ConfigurationClassPostProcessor 標記爲已經處理
processedBeans.add(ppName);
}
}
//TODO:設置排序,不重要
sortPostProcessors(currentRegistryProcessors, beanFactory);
//TODO:合併兩個集合,將spring自定義的Processors加入到registryProcessors中,可以看到所謂的currentRegistryProcessors就是一個過渡的
registryProcessors.addAll(currentRegistryProcessors);
//TODO:真正的開始調用BeanDefinitionRegistryPostProcessor中的方法
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
//TODO:清空currentRegistryProcessors,這裏就清除了 ConfigurationClassPostProcessor
currentRegistryProcessors.clear();
我們發現又定義了一個currentRegistryProcessors集合,這個集合其實就是用來存放待處理的BeanFactoryPostProcessor實現類。
通過如下這一句,spring獲得了內部自動創建的,並且實現了BeanDefinitionRegistryPostProcessor接口的實現類。之前我們討論過,在spring初始化過程中,會爲我們自動創建六個重要的對象,這六個重要的對象中,有一個就實現了這個接口,這個就是ConfigurationClassPostProcessor
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
通過這一句代碼,spring就獲取了創建的ConfigurationClassPostProcessor對象。
我們可以看到處理的代碼很簡單,只是將這個對象放入currentRegistryProcessors集合中,並在invokeBeanDefinitionRegistryPostProcessors執行之後,就清空了currentRegistryProcessors集合,其中invokeBeanDefinitionRegistryPostProcessors底部就是完成ConfigurationClassPostProcessor對象中postProcessBeanDefinitionRegistry方法的回調,這個方法中就完成了包的掃描和beanDefinition的註冊。
3、之後,調用實現了Ordered接口的BeanDefinitionRegistryPostProcessor和還沒有被調用的BeanDefinitionRegistryPostProcessor對象。這個不太重要,但是套路都是一個
// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
//TODO:開始調用實現了Ordered接口的 BeanDefinitionRegistryPostProcessor 類
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
//TODO:和上面的操作一樣,但是這個時候 currentRegistryProcessors 中只會有實現了Ordered接口的BeanDefinitionRegistryPostProcessor
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
//TODO:最後,調用其他的BeanDefinitionRegistryPostProcessors,直到沒有更多的BeanDefinitionRegistryPostProcessors實現類
//TODO:簡單點說這裏就是在掃除剩餘的沒被調用的BeanDefinitionRegistryPostProcessors實例
boolean reiterate = true;
while (reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
}
4、之後回調BeanFactoryPostProcessor對象中的postProcessBeanFactory方法
// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
//TODO:到這裏,調用postProcessBeanFactory(即BeanDefinitionRegistryPostProcessors的父類)的回調方法,這裏面就有針對@Configuration類的增強操作
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
後面的代碼大同小異,只是針對spring框架中內部實現了BeanFactoryPostProcessor接口的類,整個方法梳理到這裏,我們至少可以得出一個結論。在這個比較複雜的方法中,spring是先處理的BeanDefinitionRegistryPostProcessor的回調,再處理的BeanFactoryPostProcessor的回調(或者你會說廢話)但是接下來的東西就比較重要了,我們說過spring內部定義的一個類ConfigurationClassPostProcessor即實現了BeanDefinitionRegistryPostProcessor接口,也實現了BeanFactoryPostProcessor接口,那麼根據我們剛纔得出的結論,我們就可以得出,spring是先回調ConfigurationClassPostProcessor類中的postProcessBeanDefinitionRegistry方法,再回調ConfigurationClassPostProcessor類中的postProcessBeanFactory方法。
上一篇博客中,我們詳細介紹了spring回調ConfigurationClassPostProcessor類中的postProcessBeanDefinitionRegistry方法的操作,spring就是在這個方法底層完成了掃描和@Import註解的處理,同時也標記出了@Configuration類,這個方法的回調工作就完成了。但是我們開頭說了,針對@Configuration標記的類,可不簡單的標記掃描註冊就完事,至少還要有個代理。至少要避免我們開頭那種操作(調用兩次實例化方法的操作)
@Configuration的面紗
從 ConfigurationClassPostProcessor 回調postProcessBeanFactory方法說起。
/**
* TODO:ConfigurationClassPostProcessor第243行
* TODO:這裏會完成對@Configuration的增強處理
* Prepare the Configuration classes for servicing bean requests at runtime
* by replacing them with CGLIB-enhanced subclasses.
*/
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
int factoryId = System.identityHashCode(beanFactory);
if (this.factoriesPostProcessed.contains(factoryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + beanFactory);
}
this.factoriesPostProcessed.add(factoryId);
if (!this.registriesPostProcessed.contains(factoryId)) {
// BeanDefinitionRegistryPostProcessor hook apparently not supported...
// Simply call processConfigurationClasses lazily at this point then.
//如果配置類沒有註冊的話,完成一次註冊
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
}
//TODO:對@Configuration實現增強處理
enhanceConfigurationClasses(beanFactory);
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
於是我們發現有個enhanceConfigurationClasses的方法,enhance就是增強的意思。說明spring底層對@Configuration標記的類進行了一個增強。繼續進入
/**
* TODO:onfigurationClassPostProcessor 第338行
* TODO:對@Configuration進行增強處理
* Post-processes a BeanFactory in search of Configuration class BeanDefinitions;
* any candidates are then enhanced by a {@link ConfigurationClassEnhancer}.
* Candidate status is determined by BeanDefinition attribute metadata.
* @see ConfigurationClassEnhancer
*/
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
for (String beanName : beanFactory.getBeanDefinitionNames()) {
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
//TODO://是否是一個全代理的類(是否加了@Configuration)
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef)) {
if (!(beanDef instanceof AbstractBeanDefinition)) {
throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +
beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
}
else if (logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) {
logger.info("Cannot enhance @Configuration bean definition '" + beanName +
"' since its singleton instance has been created too early. The typical cause " +
"is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +
"return type: Consider declaring such methods as 'static'.");
}
//TODO:如果加了@Configuration 則放入configBeanDefs集合中
configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
}
}
if (configBeanDefs.isEmpty()) {
// nothing to enhance -> return immediately
return;
}
//TODO:對@Configuration的類進行增強
ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
AbstractBeanDefinition beanDef = entry.getValue();
// If a @Configuration class gets proxied, always proxy the target class
beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
try {
// Set enhanced subclass of the user-specified bean class
Class<?> configClass = beanDef.resolveBeanClass(this.beanClassLoader);
if (configClass != null) {
//TODO:進行增強
Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
if (configClass != enhancedClass) {
if (logger.isTraceEnabled()) {
logger.trace(String.format("Replacing bean definition '%s' existing class '%s' with " +
"enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName()));
}
beanDef.setBeanClass(enhancedClass);
}
}
}
catch (Throwable ex) {
throw new IllegalStateException("Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
}
}
}
可以看到這個方法比較簡單,也就是遍歷了BeanDefinition的名字,然後通過名字取出指定的BeanDefinition ,判斷這個BeanDefinition是否是@Configuration標記的類,如果是則放入configBeanDefs集合中。之後遍歷這個集合對每一個@Configuration進行代理操作。所以核心就是下面這一行
Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
繼續往下
/**
* TODO:ConfigurationClassEnhancer中的第97行
* Loads the specified class and generates a CGLIB subclass of it equipped with
* container-aware callbacks capable of respecting scoping and other bean semantics.
* @return the enhanced subclass
*/
public Class<?> enhance(Class<?> configClass, @Nullable ClassLoader classLoader) {
if (EnhancedConfiguration.class.isAssignableFrom(configClass)) {
if (logger.isDebugEnabled()) {
logger.debug(String.format("Ignoring request to enhance %s as it has " +
"already been enhanced. This usually indicates that more than one " +
"ConfigurationClassPostProcessor has been registered (e.g. via " +
"<context:annotation-config>). This is harmless, but you may " +
"want check your configuration and remove one CCPP if possible",
configClass.getName()));
}
return configClass;
}
//TODO:利用CGLIB創建增強類,newEnhancer完成具體的增強屬性的設置
Class<?> enhancedClass = createClass(newEnhancer(configClass, classLoader));
if (logger.isTraceEnabled()) {
logger.trace(String.format("Successfully enhanced %s; enhanced class name is: %s",
configClass.getName(), enhancedClass.getName()));
}
return enhancedClass;
}
通過spring本身的英文註釋就能看出,這是一個通過CGLIB生成代理子類的方法(這也就是我爲啥要在開頭列出一個CGLIB的實例的原因),如果不熟悉CGLIB的就看文章開頭的那個實例。
之後進入到createClass中的newEnhancer方法中
/**
* TODO:ConfigurationClassEnhancer第122行
* TODO:創建一個基於CGLIB的增強類
* Creates a new CGLIB {@link Enhancer} instance.
*/
private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) {
Enhancer enhancer = new Enhancer();
//TODO:將當前配置了設置成父類
enhancer.setSuperclass(configSuperClass);
//TODO:讓代理類實現EnhancedConfiguration接口,這個接口繼承了BeanFactoryAware接口,可讓我們的代理類獲得BeanFactory便於重新註冊相關bean
enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});
enhancer.setUseFactory(false);//TODO:代理類的產生不利用工廠模式
//TODO:命名策略
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
//TODO:設置CGLIB的生成策略
enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
//TODO:設置最終代理類的回調攔截器
enhancer.setCallbackFilter(CALLBACK_FILTER);
enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
//TODO:返回生成的代理類
return enhancer;
}
文章開頭的那個實例中說過,CGLIB的代理的增強邏輯主要就在攔截器中,我們看到, enhancer.setCallbackFilter(CALLBACK_FILTER);這個不就是設置代理的邏輯麼,繼續進入
// The callbacks to use. Note that these callbacks must be stateless.
private static final Callback[] CALLBACKS = new Callback[] {
new BeanMethodInterceptor(),
new BeanFactoryAwareMethodInterceptor(),
NoOp.INSTANCE
};
private static final ConditionalCallbackFilter CALLBACK_FILTER = new ConditionalCallbackFilter(CALLBACKS);
發現給@Configuration標記的類主要的代理邏輯就在BeanMethodInterceptor
和BeanFactoryAwareMethodInterceptor
中重點看這兩個類中的intercept方法即可
BeanMethodInterceptor
這個主要就是針對調用@Configuration標記的類中的@Bean方法的攔截操作
/**
* TODO:針對@Bean方法的增強
* Enhance a {@link Bean @Bean} method to check the supplied BeanFactory for the
* existence of this bean object.
* @throws Throwable as a catch-all for any exception that may be thrown when invoking the
* super implementation of the proxied method i.e., the actual {@code @Bean} method
*/
@Override
@Nullable
public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs,
MethodProxy cglibMethodProxy) throws Throwable {
//TODO:獲取beanFactory容器
ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance);
String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod);
// Determine whether this bean is a scoped-proxy
if (BeanAnnotationHelper.isScopedProxy(beanMethod)) {
String scopedBeanName = ScopedProxyCreator.getTargetBeanName(beanName);
if (beanFactory.isCurrentlyInCreation(scopedBeanName)) {
beanName = scopedBeanName;
}
}
// To handle the case of an inter-bean method reference, we must explicitly check the
// container for already cached instances.
// First, check to see if the requested bean is a FactoryBean. If so, create a subclass
// proxy that intercepts calls to getObject() and returns any cached bean instance.
// This ensures that the semantics of calling a FactoryBean from within @Bean methods
// is the same as that of referring to a FactoryBean within XML. See SPR-6602.
//TODO:處理@Bean方法返回FactroyBean的情況
/**
* TODO:首先,檢查@Bean方法返回的是否是一個FactoryBean,如果是,則創建一個返回的FactoryBean的代理類
* TODO:底層調用FactoryBean中的getObject方法,然後返回這個對象。
*/
if (factoryContainsBean(beanFactory, BeanFactory.FACTORY_BEAN_PREFIX + beanName) &&
factoryContainsBean(beanFactory, beanName)) {
Object factoryBean = beanFactory.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName);
if (factoryBean instanceof ScopedProxyFactoryBean) {
// Scoped proxy factory beans are a special case and should not be further proxied
}
else {
//TODO:針對BeanFactory的增強操作,並調用getObject方法
// It is a candidate FactoryBean - go ahead with enhancement
return enhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName);
}
}
//TODO:針對普通的bean的處理
//TODO:爲了避免出現嵌套調用的問題 isCurrentlyInvokedFactoryMethod
if (isCurrentlyInvokedFactoryMethod(beanMethod)) {
// The factory is calling the bean method in order to instantiate and register the bean
// (i.e. via a getBean() call) -> invoke the super implementation of the method to actually
// create the bean instance.
if (logger.isInfoEnabled() &&
BeanFactoryPostProcessor.class.isAssignableFrom(beanMethod.getReturnType())) {
logger.info(String.format("@Bean method %s.%s is non-static and returns an object " +
"assignable to Spring's BeanFactoryPostProcessor interface. This will " +
"result in a failure to process annotations such as @Autowired, " +
"@Resource and @PostConstruct within the method's declaring " +
"@Configuration class. Add the 'static' modifier to this method to avoid " +
"these container lifecycle issues; see @Bean javadoc for complete details.",
beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName()));
}
//TODO:調用@Configuration類中的目標方法
return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
}
return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
}
整體來看這個方法分爲三個分支,針對web操作中,@Bean註解的方法返回的bean是否是一個域級的代理;@Bean註解的方法返回的bean是否是一個FactoryBean;以及@Bean註解的方法返回的bean是一個普通的bean,如何避免被重複調用的問題,都有處理
其中isCurrentlyInvokedFactoryMethod這個判斷方法就是爲了避免我們開頭實例中兩次執行的情況。
BeanFactoryAwareMethodInterceptor
這個是針對如果這個配置類實現了BeanFactoryAware接口的攔截操作
@Override
@Nullable
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
Field field = ReflectionUtils.findField(obj.getClass(), BEAN_FACTORY_FIELD);
Assert.state(field != null, "Unable to find generated BeanFactory field");
field.set(obj, args[0]);
// Does the actual (non-CGLIB) superclass implement BeanFactoryAware?
// If so, call its setBeanFactory() method. If not, just exit.
if (BeanFactoryAware.class.isAssignableFrom(ClassUtils.getUserClass(obj.getClass().getSuperclass()))) {
return proxy.invokeSuper(obj, args);
}
return null;
}
這個方法就簡單的多。只是一個簡單的判斷,之後直接調用
總結
整篇博客預熱較久,但是針對@Configuration與@ComponentScan和@Import等註解有何區別,這裏似乎可以有個結論了:@Configuration標記的類在spring中會被將對應的BeanDefinition屬性configurationClass標記爲FULL,而其他的則會將BeanDefinition屬性configurationClass標記爲lite(中文爲:部分)。另一個最大的區別就是加上了@Configuration註解的類,spring底層會用CGLIB對這個類做一個代理,而其他註解則不會。這就是@Configuration最特殊的地方,也是最牛逼的地方。