Spring 源碼學習筆記(六)加載自定義beanFactoryPostProcessor

首先回顧下整個流程:

先新建一個BeanFactoryPostProcessor,然後在配置文件中注入這個類

public class MyPostProcessor implements BeanFactoryPostProcessor {
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		System.out.println("==> come to myPostProcessor ...");
	}
}
<bean id="myPostProcessor" class="org.springframework.MyPostProcessor"/>

下面跟進一下代碼:

refresh() ——> invokeBeanFactoryPostProcessors(beanFactory) ——> PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors())

public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

		// Invoke BeanDefinitionRegistryPostProcessors first, if any.
		Set<String> processedBeans = new HashSet<>();

		// 1.判斷beanFactory是否爲BeanDefinitionRegistry,beanFactory爲DefaultListableBeanFactory,
		// 而DefaultListableBeanFactory實現了BeanDefinitionRegistry接口,因此這邊爲true
		if (beanFactory instanceof BeanDefinitionRegistry) {
			BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
			// 用於存放普通的BeanFactoryPostProcessor
			List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
			// 用於存放BeanDefinitionRegistryPostProcessor
			List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

			// 2.首先處理入參中的beanFactoryPostProcessors
			// 遍歷所有的beanFactoryPostProcessors, 將BeanDefinitionRegistryPostProcessor和普通BeanFactoryPostProcessor區分開
			for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
				if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
					BeanDefinitionRegistryPostProcessor registryProcessor =
							(BeanDefinitionRegistryPostProcessor) postProcessor;
					registryProcessor.postProcessBeanDefinitionRegistry(registry);
					registryProcessors.add(registryProcessor);
				}
				else {
					regularPostProcessors.add(postProcessor);
				}
			}

			// 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.
			// 用於保存本次要執行的BeanDefinitionRegistryPostProcessor
			List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

			// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
			// 3.調用所有實現PriorityOrdered接口的BeanDefinitionRegistryPostProcessor實現類
			// 找出所有實現BeanDefinitionRegistryPostProcessor接口的Bean的beanName
			String[] postProcessorNames =
					beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				//校驗是否實現了PriorityOrdered接口
				if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
					//獲取ppName對應的bean實例, 添加到currentRegistryProcessors中,
					// beanFactory.getBean: 這邊getBean方法會觸發創建ppName對應的bean對象, 目前暫不深入解析
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					// 將要被執行的加入processedBeans,避免後續重複執行
					processedBeans.add(ppName);
				}
			}
			//進行排序(根據是否實現PriorityOrdered、Ordered接口和order值來排序)
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			//添加到registryProcessors(用於最後執行postProcessBeanFactory方法)
			registryProcessors.addAll(currentRegistryProcessors);
			//遍歷currentRegistryProcessors, 執行postProcessBeanDefinitionRegistry方法
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
			//執行完畢後, 清空currentRegistryProcessors
			currentRegistryProcessors.clear();

			// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
			// 4.調用所有實現了Ordered接口的BeanDefinitionRegistryPostProcessor實現類(過程跟上面的步驟3基本一樣)
			// 找出所有實現BeanDefinitionRegistryPostProcessor接口的類, 這邊重複查找是因爲執行完上面的BeanDefinitionRegistryPostProcessor,
			// 可能會新增了其他的BeanDefinitionRegistryPostProcessor, 因此需要重新查找
			postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				// 校驗是否實現了Ordered接口,並且還未執行過
				if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			// 遍歷currentRegistryProcessors, 執行postProcessBeanDefinitionRegistry方法
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
			currentRegistryProcessors.clear();

			// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
			// 5.最後, 調用所有剩下的BeanDefinitionRegistryPostProcessors
			boolean reiterate = true;
			while (reiterate) {
				reiterate = false;
				//找出所有實現BeanDefinitionRegistryPostProcessor接口的類
				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);
						// 如果有BeanDefinitionRegistryPostProcessor被執行, 則有可能會產生新的BeanDefinitionRegistryPostProcessor,
						// 因此這邊將reiterate賦值爲true, 代表需要再循環查找一次
						reiterate = true;
					}
				}
				sortPostProcessors(currentRegistryProcessors, beanFactory);
				registryProcessors.addAll(currentRegistryProcessors);
				// 遍歷currentRegistryProcessors, 執行postProcessBeanDefinitionRegistry方法
				invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
				currentRegistryProcessors.clear();
			}

			// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
			// 6.調用所有BeanDefinitionRegistryPostProcessor的postProcessBeanFactory方法(BeanDefinitionRegistryPostProcessor繼承自BeanFactoryPostProcessor)
			invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
			// 7.最後, 調用入參beanFactoryPostProcessors中的普通BeanFactoryPostProcessor的postProcessBeanFactory方法
			invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
		}

		else {
			// Invoke factory processors registered with the context instance.
			invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
		}

		// 到這裏 , 入參beanFactoryPostProcessors和容器中的所有BeanDefinitionRegistryPostProcessor已經全部處理完畢,
		// 下面開始處理容器中的所有BeanFactoryPostProcessor

		// Do not initialize FactoryBeans here: We need to leave all regular beans
		// uninitialized to let the bean factory post-processors apply to them!
		// 8.找出所有實現BeanFactoryPostProcessor接口的類
		String[] postProcessorNames =
				beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

		// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
		// Ordered, and the rest.
		// 用於存放實現了PriorityOrdered接口的BeanFactoryPostProcessor
		List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
		// 用於存放實現了Ordered接口的BeanFactoryPostProcessor的beanName
		List<String> orderedPostProcessorNames = new ArrayList<>();
		// 用於存放普通BeanFactoryPostProcessor的beanName
		List<String> nonOrderedPostProcessorNames = new ArrayList<>();
		// 遍歷postProcessorNames, 將BeanFactoryPostProcessor按實現PriorityOrdered、實現Ordered接口、普通三種區分開
		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);
			}
		}

		// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
		// 9.調用所有實現PriorityOrdered接口的BeanFactoryPostProcessor
		// 對priorityOrderedPostProcessors排序
		sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
		// 遍歷priorityOrderedPostProcessors, 執行postProcessBeanFactory方法
		invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

		// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
		// 10.調用所有實現Ordered接口的BeanFactoryPostProcessor
		List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
		for (String postProcessorName : orderedPostProcessorNames) {
			// 獲取postProcessorName對應的bean實例, 添加到orderedPostProcessors, 準備執行
			orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		}
		sortPostProcessors(orderedPostProcessors, beanFactory);
		//遍歷orderedPostProcessors, 執行postProcessBeanFactory方法
		invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

		// Finally, invoke all other BeanFactoryPostProcessors.
		// 11.調用所有剩下的BeanFactoryPostProcessor
		List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
		for (String postProcessorName : nonOrderedPostProcessorNames) {
			nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		}
		//遍歷nonOrderedPostProcessors, 執行postProcessBeanFactory方法
		invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

		// Clear cached merged bean definitions since the post-processors might have
		// modified the original metadata, e.g. replacing placeholders in values...
		// 12.清除元數據緩存(mergedBeanDefinitions、allBeanNamesByType、singletonBeanNamesByType),
		// 因爲後處理器可能已經修改了原始元數據,例如, 替換值中的佔位符...
		beanFactory.clearMetadataCache();
	}

1、整個 invokeBeanFactoryPostProcessors 方法圍繞兩個接口,BeanDefinitionRegistryPostProcessor 和 BeanFactoryPostProcessor,其中 BeanDefinitionRegistryPostProcessor 繼承了 BeanFactoryPostProcessor 。BeanDefinitionRegistryPostProcessor 主要用來在常規 BeanFactoryPostProcessor 檢測開始之前註冊其他 Bean 定義,說的簡單點,就是 BeanDefinitionRegistryPostProcessor 具有更高的優先級,執行順序在 BeanFactoryPostProcessor 之前。

2、整個 invokeBeanFactoryPostProcessors 方法操作了 3 種 bean 對象:

  •     入參 beanFactoryPostProcessors:取的是 AbstractApplicationContext 類的 beanFactoryPostProcessors 屬性值,也就是在之前已經添加到 beanFactoryPostProcessors 中的 BeanFactoryPostProcessor。
  •     BeanDefinitionRegistryPostProcessor 接口實現類:實現了 BeanDefinitionRegistryPostProcessor 接口,並且註冊到 Spring IoC容器中。
  •     常規 BeanFactoryPostProcessor 接口實現類:實現了 BeanFactoryPostProcessor 接口,並且註冊到 Spring IoC容器中。

如果將自定義 BeanFactoryPostProcessor 放到AbstractApplicationContext 類的 beanFactoryPostProcessors 屬性中,在‘’入參 beanFactoryPostProcessors“時就能加載到?如果要加入到入參beanFactoryPostProcessors(當項目啓動時確保在refresh之前加載到這個 BeanFactoryPostProcessor),可以新建一個 ApplicationContextInitializer 的實現類 SpringApplicationContextInitializer ,並在 initialize 方法中寫我們的邏輯 。

package com.joonwhee.open.demo.spring;
 
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
 
 
public class SpringApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
 
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        FirstBeanDefinitionRegistryPostProcessor firstBeanDefinitionRegistryPostProcessor = new FirstBeanDefinitionRegistryPostProcessor();
        // 將自定義的firstBeanDefinitionRegistryPostProcessor添加到應用上下文中
        applicationContext.addBeanFactoryPostProcessor(firstBeanDefinitionRegistryPostProcessor);
        // ...自定義操作
        System.out.println("SpringApplicationContextInitializer#initialize");
    }
}
<context-param>
    <param-name>contextInitializerClasses</param-name>
    <param-value>
        com.joonwhee.open.demo.spring.SpringApplicationContextInitializer
    </param-value>
</context-param>

擴展: 那麼爲什麼要這麼做呢? 因爲 customizeContext 方法,是 Spring 提供給開發者的一個擴展點,用於自定義應用上下文,並且在 refresh() 方法前就被調用。 下面說一下項目啓動時 customizeConxt 的加載位置。

web.xml 是一個使用了 Spring 框架的項目的最基本的配置,配置了 ContextLoaderListener 和 contextConfigLocation。其中 ContextLoaderListener 是 Spring 的入口,而 contextConfigLocation 是 Spring 配置文件的路徑。下面將從 ContextLoaderListener#contextInitialized 開始 IoC 的構建。

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
         http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <display-name>open-joonwhee-service WAR</display-name>
 
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            classpath*:config/spring/appcontext-*.xml
        </param-value>
    </context-param>
 
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
</web-app>

進入 ContextLoaderListener#contextInitialized 方法之前,由於 ContextLoaderListener 繼承了 ContextLoader,需要先將 ContextLoader 的成員變量初始化。在 ContextLoader 的成員變量中,defaultStrategies 屬性的初始化比較重要,下面拿出來單獨介紹。

private static final String DEFAULT_STRATEGIES_PATH = "ContextLoader.properties";
 
 
private static final Properties defaultStrategies;
 
static {
    // Load default strategy implementations from properties file.
    // This is currently strictly internal and not meant to be customized
    // by application developers.
    try {
        // 1.根據 DEFAULT_STRATEGIES_PATH(ContextLoader.properties) 和 ContextLoader.class 構建 ClassPathResource,
        // path在這邊爲相對路徑,全路徑爲:org.springframework.web.context.ContextLoader.properties
        ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class);
        // 2.加載resource的屬性,在這邊我們拿到了默認的WebApplicationContext,即:XmlWebApplicationContext
        defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
    } catch (IOException ex) {
        throw new IllegalStateException("Could not load 'ContextLoader.properties': " + ex.getMessage());
    }
}

接着,正式進入 ContextLoaderListener#contextInitialized 方法

@Override
public void contextInitialized(ServletContextEvent event) {
    initWebApplicationContext(event.getServletContext());
}
 
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
    // 1.校驗WebApplicationContext 是否已經初始化過,如果已經初始化,則拋出異常
    if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
        throw new IllegalStateException(
                "Cannot initialize context because there is already a root application context present - " +
                        "check whether you have multiple ContextLoader* definitions in your web.xml!");
    }
 
    Log logger = LogFactory.getLog(ContextLoader.class);
    servletContext.log("Initializing Spring root WebApplicationContext");
    if (logger.isInfoEnabled()) {
        logger.info("Root WebApplicationContext: initialization started");
    }
    long startTime = System.currentTimeMillis();
 
    try {
        // Store context in local instance variable, to guarantee that
        // it is available on ServletContext shutdown.
        if (this.context == null) {
            // 2.創建一個WebApplicationContext並保存到context屬性
            this.context = createWebApplicationContext(servletContext);
        }
        if (this.context instanceof ConfigurableWebApplicationContext) {
            ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
            if (!cwac.isActive()) {
                // The context has not yet been refreshed -> provide services such as
                // setting the parent context, setting the application context id, etc
                if (cwac.getParent() == null) {
                    // The context instance was injected without an explicit parent ->
                    // determine parent for root web application context, if any.
                    ApplicationContext parent = loadParentContext(servletContext);
                    cwac.setParent(parent);
                }
                // 3.配置和刷新web應用上下文
                configureAndRefreshWebApplicationContext(cwac, servletContext);
            }
        }
        // 4.設置WebApplicationContext屬性
        servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
 
        ClassLoader ccl = Thread.currentThread().getContextClassLoader();
        if (ccl == ContextLoader.class.getClassLoader()) {
            currentContext = this.context;
        } else if (ccl != null) {
            currentContextPerThread.put(ccl, this.context);
        }
 
        if (logger.isDebugEnabled()) {
            logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +
                    WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
        }
        if (logger.isInfoEnabled()) {
            long elapsedTime = System.currentTimeMillis() - startTime;
            logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
        }
 
        return this.context;
    } catch (RuntimeException ex) {
        logger.error("Context initialization failed", ex);
        servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
        throw ex;
    } catch (Error err) {
        logger.error("Context initialization failed", err);
        servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
        throw err;
    }
}

其中第三步 configureAndRefreshWebApplicationContext 配置刷新應用上下文

protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
    // 1.如果應用上下文id是原始默認值,則根據相關信息生成一個更有用的
    if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
        // The application context id is still set to its original default value
        // -> assign a more useful id based on available information
        // 1.1 從servletContext中解析初始化參數contextId(可以在web.xml中配置)
        String idParam = sc.getInitParameter(CONTEXT_ID_PARAM);
        if (idParam != null) {
            // 1.1.1 如果idParam不爲空, 則設置爲wac的Id屬性
            wac.setId(idParam);
        } else {
            // Generate default id...
            // 1.1.2 如果idParam爲空, 則生成默認的id, 例如: org.springframework.web.context.WebApplicationContext:
            wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
                    ObjectUtils.getDisplayString(sc.getContextPath()));
        }
    }
 
    // 2.爲應用上下文設置servletContext
    wac.setServletContext(sc);
    // 3.從servletContext中解析初始化參數contextConfigLocation(可以在web.xml中配置, 這個參數一般我們都會設置)
    String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
    if (configLocationParam != null) {
        // 4.設置wac的configLocations屬性值爲configLocationParam
        wac.setConfigLocation(configLocationParam);
    }
 
    // The wac environment's #initPropertySources will be called in any case when the context
    // is refreshed; do it eagerly here to ensure servlet property sources are in place for
    // use in any post-processing or initialization that occurs below prior to #refresh
    ConfigurableEnvironment env = wac.getEnvironment();
    if (env instanceof ConfigurableWebEnvironment) {
        // 5.初始化屬性源(主要是將servletContextInitParams的佔位類替換成sc)
        ((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
    }
 
    // 6.自定義上下文
    customizeContext(sc, wac);
    // 7.應用上下文的刷新
    wac.refresh();
}

第六步 customizeContext 自定義上下文

protected void customizeContext(ServletContext sc, ConfigurableWebApplicationContext wac) {
    // 1.確定應用上下文的初始化類
    List<Class<ApplicationContextInitializer<ConfigurableApplicationContext>>> initializerClasses =
            determineContextInitializerClasses(sc);
 
    // 2.如果initializerClasses不爲空, 遍歷處理initializerClasses
    for (Class<ApplicationContextInitializer<ConfigurableApplicationContext>> initializerClass : initializerClasses) {
        Class<?> initializerContextClass =
                GenericTypeResolver.resolveTypeArgument(initializerClass, ApplicationContextInitializer.class);
        if (initializerContextClass != null && !initializerContextClass.isInstance(wac)) {
            throw new ApplicationContextException(String.format(
                    "Could not apply context initializer [%s] since its generic parameter [%s] " +
                            "is not assignable from the type of application context used by this " +
                            "context loader: [%s]", initializerClass.getName(), initializerContextClass.getName(),
                    wac.getClass().getName()));
        }
        // 3.實例化initializerClass, 並添加到contextInitializers中
        this.contextInitializers.add(BeanUtils.instantiateClass(initializerClass));
    }
 
    AnnotationAwareOrderComparator.sort(this.contextInitializers);
    // 4.遍歷實例化後的contextInitializers
    for (ApplicationContextInitializer<ConfigurableApplicationContext> initializer : this.contextInitializers) {
        // 5.調用initializer的initialize方法,進行自定義初始化wac操作
        initializer.initialize(wac);
    }
}

3、整個 invokeBeanFactoryPostProcessors 方法多次調用getBeanNamesForType,如何找出所有實現類的beanName?下面挖一下(之前妄想猜測有能通過接口反射找到所有實現類的方法,實際上只是將配置文件中的bean加載到beanFactory,然後再進行遍歷驗證來處理)

// 找出所有實現BeanDefinitionRegistryPostProcessor接口的Bean的beanName
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
//方法簽名
//第一個參數type表示要查找的bean的類型
//includeNonSingletons 是否考慮非單例bean
//allowEagerInit 是否允許提早初始化
String[] getBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit);


//具體的實現代碼,我們從DefaultListableBeanFactory中分析
public String[] getBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
        //配置還未被凍結或者類型爲null或者不允許早期初始化
		if (!isConfigurationFrozen() || type == null || !allowEagerInit) {
			return doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, allowEagerInit);
		}
		//值得注意的是,不管type是否不爲空,allowEagerInit是否爲true
		//只要isConfigurationFrozen()爲false就一定不會走這裏
		//因爲isConfigurationFrozen()爲false的時候表示BeanDefinition
		//可能還會發生更改和添加,所以不能進行緩存
		//如果允許非單例的bean,那麼從保存所有bean的集合中獲取,否則從
		//單例bean中獲取
		Map<Class<?>, String[]> cache =
				(includeNonSingletons ? this.allBeanNamesByType : this.singletonBeanNamesByType);
		String[] resolvedBeanNames = cache.get(type);
		if (resolvedBeanNames != null) {
			return resolvedBeanNames;
		}
		//如果緩存中沒有獲取到,那麼只能重新獲取,獲取到之後就存入緩存
		resolvedBeanNames = doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, true);
		if (ClassUtils.isCacheSafe(type, getBeanClassLoader())) {
			cache.put(type, resolvedBeanNames);
		}
		return resolvedBeanNames;
	}

//DefaultListableBeanFactory
private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
		List<String> result = new ArrayList<String>();

		// Check all bean definitions.
		for (String beanName : this.beanDefinitionNames) {
			// Only consider bean as eligible if the bean name
			// is not defined as alias for some other bean.
			//如果是別名,跳過(這個集合會保存所有的主beanName,並且不會
			//保存別名,別名由BeanFactory中別名map維護,這裏個人認爲是一種防禦性編程)
			if (!isAlias(beanName)) {
				try {
				    //獲取合併的BeanDefinition,合併的BeanDefinition是指
				    //spring整合了父BeanDefinition的屬性,將其他類型的
				    //BeanDefinition變成了RootBeanDefintion
					RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
					// Only check bean definition if it is complete.
					//抽象的BeanDefinition是不做考慮,抽象的就是拿來繼承的
					//如果允許早期初始化,那麼直接短路,進入方法體
					//如果不允許早期初始化,那麼需要進一步判斷,如果是不允許早期初始化的,
					//並且beanClass已經被加載或者它是可以早期初始化的,那麼如果當前bean是工廠bean,並且指定的bean又是工廠
					//那麼這個bean就必須被早期初始化,也就是說就不符合我們制定的allowEagerInit爲false的情況,直接跳過
					if (!mbd.isAbstract() && (allowEagerInit ||
							((mbd.hasBeanClass() || !mbd.isLazyInit() || isAllowEagerClassLoading())) &&
									!requiresEagerInitForType(mbd.getFactoryBeanName()))) {
						// In case of FactoryBean, match object created by FactoryBean.
						//如果當前bean是工廠bean
						boolean isFactoryBean = isFactoryBean(beanName, mbd);
						//如果允許早期初始化,那麼基本上會調用最後的isTypeMatch方法
						//這個方法會導致工廠的實例化,但是當前不允許進行早期實例化
						//在不允許早期實例化的情況下,如果當前bean是工廠bean,那麼它只能在已經被創建的情況下調用isTypeMatch進行匹配判斷
						//否則只能宣告匹配失敗,返回false
						boolean matchFound = (allowEagerInit || !isFactoryBean || containsSingleton(beanName)) &&
								(includeNonSingletons || isSingleton(beanName)) && isTypeMatch(beanName, type);
						//如果沒有匹配到並且它是個工廠bean,那麼加上&前綴,表示我要獲取FactoryBean類型的bean
						if (!matchFound && isFactoryBean) {
							// In case of FactoryBean, try to match FactoryBean instance itself next.
							beanName = FACTORY_BEAN_PREFIX + beanName;
							matchFound = (includeNonSingletons || mbd.isSingleton()) && isTypeMatch(beanName, type);
						}
						//找到便記錄到result集合中,等待返回
						if (matchFound) {
							result.add(beanName);
						}
					}
				}
				catch (CannotLoadBeanClassException ex) {
					if (allowEagerInit) {
						throw ex;
					}
					// Probably contains a placeholder: let's ignore it for type matching purposes.
					if (this.logger.isDebugEnabled()) {
						this.logger.debug("Ignoring bean class loading failure for bean '" + beanName + "'", ex);
					}
					onSuppressedException(ex);
				}
				catch (BeanDefinitionStoreException ex) {
					if (allowEagerInit) {
						throw ex;
					}
					// Probably contains a placeholder: let's ignore it for type matching purposes.
					if (this.logger.isDebugEnabled()) {
						this.logger.debug("Ignoring unresolvable metadata in bean definition '" + beanName + "'", ex);
					}
					onSuppressedException(ex);
				}
			}
		}

		// Check manually registered singletons too.
		//從單例註冊集合中獲取,這個單例集合是保存spring內部注入的單例對象
		//它們有特點就是沒有BeanDefinition
		for (String beanName : this.manualSingletonNames) {
			try {
				// In case of FactoryBean, match object created by FactoryBean.
				//如果是工廠bean,那麼調用其getObjectType去匹配是否符合指定類型
				if (isFactoryBean(beanName)) {
					if ((includeNonSingletons || isSingleton(beanName)) && isTypeMatch(beanName, type)) {
						result.add(beanName);
						// Match found for this bean: do not match FactoryBean itself anymore.
						continue;
					}
					// In case of FactoryBean, try to match FactoryBean itself next.
					beanName = FACTORY_BEAN_PREFIX + beanName;
				}
				//如果沒有匹配成功,那麼匹配工廠類
				// Match raw bean instance (might be raw FactoryBean).
				if (isTypeMatch(beanName, type)) {
					result.add(beanName);
				}
			}
			catch (NoSuchBeanDefinitionException ex) {
				// Shouldn't happen - probably a result of circular reference resolution...
				if (logger.isDebugEnabled()) {
					logger.debug("Failed to check manually registered singleton with name '" + beanName + "'", ex);
				}
			}
		}

		return StringUtils.toStringArray(result);
	}

RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);在查找指定類型的bean的時候,spring會對BeanDefinition進行合併,以保證某個bean信息是完整的 。

boolean isFactoryBean = isFactoryBean(beanName, mbd); 其中isFactoryBean層級較深,這裏只描述一下方法內容:首先判斷對應BeanDefinition是否存在工廠方法,如果不存在,很好說,直接判斷beanClass即可,如果存在工廠方法,那麼又得判斷是否存在factorybeanname屬性,如果不存在,那麼這是一個靜態工廠,判斷其方法的返回類型是否爲FactoryBean類型即可,如果存在,那麼事情就稍微複雜了,如果對應的factorybeanname是一個普通的類,那麼也只需要判斷其返回返回值類型即可,但是如果這個factorybeanname是一個實現了FactoryBean接口的類,那麼我們需要實例化,然後調用FactoryBean的getObjectType方法獲取到對應的對象類型,在判斷它的工廠方法的返回類型。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章