【spring原始碼系列】之【BeanDefinition】

小豬爸爸發表於2021-05-08

1. BeanDefinition簡介

前面講的解析bean標籤,本質就是將bean的資訊封裝成BeanDefinition物件的過程,最後放入容器beanDefinitionMap中。spring 要根據 BeanDefinition物件來例項化bean,只要把解析的標籤,掃描的註解類封裝成BeanDefinition物件,spring才能例項化bean。

BeanDefinition有三個實現類,ChildBeanDefinitionGenericBeanDefinitionRootBeanDefinition,三者都繼承 AbstractBeanDefinition,對三個子類共同的類資訊進行抽象。如果配置檔案中定義了父 和 子 ,則父 用 RootBeanDefinition表示,子 用 ChildBeanDefinition 表示,而沒有父 的就使用RootBeanDefinition 表示。GenericBeanDefinition 為一站式服務類。

2. BeanDefinition的屬性

上一篇文章中並未對BeanDefinition屬性作詳細分析,本文再次回到上文提到的BeanDefintionParserDelegate的方法parseBeanDefinitionAttributes方法。

public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
			@Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {
		// 解析scope標籤
		if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
			error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
		}
		else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {
			bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
		}
		else if (containingBean != null) {
			// Take default from containing bean in case of an inner bean definition.
			bd.setScope(containingBean.getScope());
		}

		// 解析abstract標籤
		if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
			bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
		}

		// 解析lazy-init標籤
		String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
		if (isDefaultValue(lazyInit)) {
			lazyInit = this.defaults.getLazyInit();
		}
		bd.setLazyInit(TRUE_VALUE.equals(lazyInit));

		// 解析 autowire 標籤
		String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
		bd.setAutowireMode(getAutowireMode(autowire));

		// 解析 depends-on 標籤
		if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
			String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
			bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
		}

		// 解析 autowire-candidate 標籤
		String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
		if (isDefaultValue(autowireCandidate)) {
			String candidatePattern = this.defaults.getAutowireCandidates();
			if (candidatePattern != null) {
				String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
				bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
			}
		}
		else {
			bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
		}

		// 解析 primary 標籤
		if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {
			bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));
		}

		// 解析 init-method 標籤
		if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
			String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
			bd.setInitMethodName(initMethodName);
		}
		else if (this.defaults.getInitMethod() != null) {
			bd.setInitMethodName(this.defaults.getInitMethod());
			bd.setEnforceInitMethod(false);
		}

		// 解析 destroy-method 標籤
		if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {
			String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);
			bd.setDestroyMethodName(destroyMethodName);
		}
		else if (this.defaults.getDestroyMethod() != null) {
			bd.setDestroyMethodName(this.defaults.getDestroyMethod());
			bd.setEnforceDestroyMethod(false);
		}

		// 解析 factory-method 標籤
		if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
			bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
		}

		// 解析 factory-bean 標籤
		if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
			bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
		}

		return bd;
	}

由於BeanDefinition的實現類都繼承自父類AbstractBeanDefinition,父類中有三個引用的屬性ConstructorArgumentValuesMutablePropertyValuesMethodOverrides,所以GenericBeanDefinition最終包含的屬性如下圖:

  • id:Bean 的唯一標識名。它必須是合法的 XMLID,在整個 XML 文件中唯一;
  • name:用來為 id 建立一個或多個別名。它可以是任意的字母符合。多個別名之間用逗號或空格分開;
  • class:用來定義類的全限定名(包名+類名)。只有子類 Bean 不用定義該屬性;
  • parent:子類 Bean 定義它所引用它的父類 Bean,這時前面的 class 屬性失效,子類 Bean 會繼承父類 Bean 的所有屬性,子類 Bean 也可以覆蓋父類 Bean 的屬性,注意:子類 Bean 和父類 Bean 是同一個 Java 類;
  • abstract(預設為"false"):用來定義 Bean 是否為抽象 Bean。它表示這個 Bean 將不會被例項化,一般用於父類 Bean,因為父類 Bean 主要是供子類 Bean 繼承使用;
  • lazy-init(預設為"false"):用來定義這個 Bean 是否實現懶初始化。如果為"false",它將在 BeanFactory 啟動時初始化所有的 SingletonBean。反之,如果為"true",它只在 Bean 請求時才開始建立 SingletonBean;
  • autowire(自動裝配,預設為"default"):它定義了 Bean 的自動裝載方式;
    --"no":不使用自動裝配功能;
    --"byName":通過 Bean 的屬性名實現自動裝配;
    --"byType":通過 Bean 的型別實現自動裝配;
    --"constructor":類似於 byType,但它是用於建構函式的引數的自動組裝;
    --"autodetect":通過 Bean 類的反省機制(introspection)決定是使用"constructor"還是使用"byType"。
  • depends-on(依賴物件):這個 Bean 在初始化時依賴的物件,這個物件會在這個 Bean 初始化之前建立;
  • init-method:用來定義 Bean 的初始化方法,它會在 Bean 組裝之後呼叫。它必須是一個無引數的方法;
  • destroy-method:用來定義 Bean 的銷燬方法,它在 BeanFactory 關閉時呼叫。同樣,它也必
    須是一個無引數的方法。它只能應用於 singletonBean。
  • factory-method:定義建立該 Bean 物件的工廠方法。它用於下面的"factory-bean",表示這個 Bean 是通過工廠方法建立,此時,"class"屬性失效。
  • factory-bean:定義建立該 Bean 物件的工廠類。如果使用了"factory-bean"則"class"屬性失效。
  • autowire-candidate:採用 xml 格式配置 bean 時,將元素的 autowire-candidate屬性設定為 false,這樣容器在查詢自動裝配物件時,將不考慮該 bean,即它不會被考慮作為其它 bean自動裝配的候選者,但是該 bean 本身還是可以使用自動裝配來注入其它 bean 的;
  • MutablePropertyValues:用於封裝標籤的資訊,其實類裡面就是有一個 list,list裡面是 PropertyValue 物件,PropertyValue 就是一個 name 和 value 屬性,用於封裝標籤的名稱和值資訊
  • ConstructorArgumentValues:用於封裝標籤的資訊,其實類裡面就是有一個 map,map 中用建構函式的引數順序作為 key,值作為 value 儲存到 map 中;
  • MethodOverrides:用於封裝 lookup-method 和 replaced-method 標籤的資訊,同樣的類裡面有一個 Set 物件新增 LookupOverride 物件和ReplaceOverride 物件。

3. component-scan標籤解析過程

3.1 流程概覽

3.2 詳細過程

前面一文提到,自定義標籤解析BeanDefinitionParserDelegate類,執行parseCustomElement方法;

public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
                // 獲取namespaceURI
		String namespaceUri = getNamespaceURI(ele);
		if (namespaceUri == null) {
			return null;
		}
                // 解析namespaceURI對應的handler類
		NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
		if (handler == null) {
			error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
			return null;
		}
                // 執行handler的解析方法
		return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
	}

上述過程主要完成以下步驟:
step1: 獲取namespaceURI;
step2: 解析namespaceURI對應的handler類;
step3:執行handler方法解析。
step1與step2前文已分析,以component-scan為例,分析step3,程式碼進入ComponentScanBeanDefinitionParserparse方法

	public BeanDefinition parse(Element element, ParserContext parserContext) {
		/**
		 * 1. 包掃描.class字尾的檔案
		 * 2. 判斷類上是否有註解
		 * 3. GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
		 *         genericBeanDefinition.setBeanClass(BeanClass.class);
		 * 4. 完成beanDefinition的註冊
		 */
		String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
		basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
		String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
				ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);

		// Actually scan for bean definitions and register them.
		// 建立掃描器
		ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
		// 掃描器掃描
		Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
		// 註冊bean包含的元件
		registerComponents(parserContext.getReaderContext(), beanDefinitions, element);

		return null;
	}

上述過程總共分為三步:
step1:configureScanner方法建立掃描器;
step2:doScan方法掃描器掃描;
step3:registerComponents註冊bean包含的元件。

進入上述step2,進入ClassPathBeanDefinitionScannerdoScan方法,

	protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
		Assert.notEmpty(basePackages, "At least one base package must be specified");
		Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
		for (String basePackage : basePackages) {
			// 掃描有註解的類並封裝成beanDefinition物件
			Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
			for (BeanDefinition candidate : candidates) {
				ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
				candidate.setScope(scopeMetadata.getScopeName());
				String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
				if (candidate instanceof AbstractBeanDefinition) {
					postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
				}
				if (candidate instanceof AnnotatedBeanDefinition) {
					// 支援@Lazy @Primary @DependOn註解
					AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
				}
				if (checkCandidate(beanName, candidate)) {
					BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
					definitionHolder =
							AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
					beanDefinitions.add(definitionHolder);
					registerBeanDefinition(definitionHolder, this.registry);
				}
			}
		}
		return beanDefinitions;
	}

上述doScan方法主要做了以下三步:
step1: findCandidateComponents掃描有註解的類並封裝成beanDefinition物件;
step2: processCommonDefinitionAnnotations方法支援@Lazy @Primary @DependOn註解;
step3:註冊BeanDefinition。

繼續進入上述step1中的findCandidateComponents方法,來到ClassPathScanningCandidateComponentProvider類的scanCandidateComponents方法,完成以下步驟:
step1: getResources遞迴獲取.class字尾的檔案;
step2: getMetadataReader方法,獲取後設資料AnnotationMetadataReadingVisitor物件,該後設資料收集了掃描類的任何資訊;
step3:判斷includeFilters是否跟後設資料中的註解匹配,如果匹配就例項化該類,建立BeanDefinition物件。

前面還有一個步驟step3:registerComponents註冊bean包含的元件還未分析,進入該方法

protected void registerComponents(
			XmlReaderContext readerContext, Set<BeanDefinitionHolder> beanDefinitions, Element element) {

		Object source = readerContext.extractSource(element);
		CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), source);

		for (BeanDefinitionHolder beanDefHolder : beanDefinitions) {
			compositeDef.addNestedComponent(new BeanComponentDefinition(beanDefHolder));
		}


		boolean annotationConfig = true;
		if (element.hasAttribute(ANNOTATION_CONFIG_ATTRIBUTE)) {
			annotationConfig = Boolean.parseBoolean(element.getAttribute(ANNOTATION_CONFIG_ATTRIBUTE));
		}
		if (annotationConfig) {
			// 如果類中的屬性有註解,註冊註解配置處理器
			Set<BeanDefinitionHolder> processorDefinitions =
					AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source);
			for (BeanDefinitionHolder processorDefinition : processorDefinitions) {
				compositeDef.addNestedComponent(new BeanComponentDefinition(processorDefinition));
			}
		}

		readerContext.fireComponentRegistered(compositeDef);
	}

隨後進入AnnotationConfigUtils.registerAnnotationConfigProcessors

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
			BeanDefinitionRegistry registry, @Nullable Object source) {

		DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
		if (beanFactory != null) {
			if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
				beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
			}
			if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
				beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
			}
		}

		Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

		// @Configuration註解的處理器ConfigurationClassPostProcessor
		if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

		// @Autowired註解的處理器AutowiredAnnotationBeanPostProcessor
		if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

		// CommonAnnotationBeanPostProcessor處理器.
		if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

		// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
		if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition();
			try {
				def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
						AnnotationConfigUtils.class.getClassLoader()));
			}
			catch (ClassNotFoundException ex) {
				throw new IllegalStateException(
						"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
			}
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

		if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
		}

		if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
		}

		return beanDefs;
	}

上面提到了三類處理器ConfigurationClassPostProcessorAutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessor,分別對不同註解作處理,最後封裝到BeanDefinition中,註冊到容器。

進入ConfigurationClassPostProcessor的processConfigBeanDefinitions方法,如下:

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
		......
		// 解析所有加了@Configuration註解的類
		ConfigurationClassParser parser = new ConfigurationClassParser(
				this.metadataReaderFactory, this.problemReporter, this.environment,
				this.resourceLoader, this.componentScanBeanNameGenerator, registry);

		Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
		Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
		do {
			// 解析@Component @ComponentScan @ComponentScans @Bean @Import @ImportResource
			parser.parse(candidates);
			parser.validate();

			......
	}

上述方法主要解析加了@Configuration的類,以及@Component @ComponentScan @ComponentScans @Bean @Import @ImportResource註解,後者是通過parse方法完成的,進入parse方法一路走下來回到processConfigurationClass方法,如下圖

protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
		......
		do {
			sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
		}
		while (sourceClass != null);
                ......
	}

隨後進入doProcessConfigurationClass方法,完成@Component @ComponentScan @ComponentScans @Bean @Import @ImportResource註解解析。

protected final SourceClass doProcessConfigurationClass(
			ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
			throws IOException {

		// 解析 @Component
		if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
			// Recursively process any member (nested) classes first
			processMemberClasses(configClass, sourceClass, filter);
		}

		// 解析 @PropertySource
		for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), PropertySources.class,
				org.springframework.context.annotation.PropertySource.class)) {
			if (this.environment instanceof ConfigurableEnvironment) {
				processPropertySource(propertySource);
			}
			else {
				logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
						"]. Reason: Environment must implement ConfigurableEnvironment");
			}
		}

		// 解析 @ComponentScan @ComponentScans
		Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
		if (!componentScans.isEmpty() &&
				!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
			for (AnnotationAttributes componentScan : componentScans) {
				// The config class is annotated with @ComponentScan -> perform the scan immediately
				Set<BeanDefinitionHolder> scannedBeanDefinitions =
						this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
				// Check the set of scanned definitions for any further config classes and parse recursively if needed
				for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
					BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
					if (bdCand == null) {
						bdCand = holder.getBeanDefinition();
					}
					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
						parse(bdCand.getBeanClassName(), holder.getBeanName());
					}
				}
			}
		}

		// 解析 @Import
		processImports(configClass, sourceClass, getImports(sourceClass), filter, true);

		// 解析 @ImportResource
		AnnotationAttributes importResource =
				AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
		if (importResource != null) {
			String[] resources = importResource.getStringArray("locations");
			Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
			for (String resource : resources) {
				String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
				configClass.addImportedResource(resolvedResource, readerClass);
			}
		}

		// 解析 @Bean 方法
		Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
		for (MethodMetadata methodMetadata : beanMethods) {
			configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
		}

		// Process default methods on interfaces
		processInterfaces(configClass, sourceClass);

		// Process superclass, if any
		if (sourceClass.getMetadata().hasSuperClass()) {
			String superclass = sourceClass.getMetadata().getSuperClassName();
			if (superclass != null && !superclass.startsWith("java") &&
					!this.knownSuperclasses.containsKey(superclass)) {
				this.knownSuperclasses.put(superclass, configClass);
				// Superclass found, return its annotation metadata and recurse
				return sourceClass.getSuperClass();
			}
		}

		// No superclass -> processing is complete
		return null;
	}

同樣跟蹤AutowiredAnnotationBeanPostProcessor類,可以看到該類完成@Autowired @Value的解析,如下圖:

public AutowiredAnnotationBeanPostProcessor() {
		this.autowiredAnnotationTypes.add(Autowired.class);
		this.autowiredAnnotationTypes.add(Value.class);
		try {
			this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
					ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
			logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
		}
		catch (ClassNotFoundException ex) {
			// JSR-330 API not available - simply skip.
		}
	}

類似跟蹤CommonAnnotationBeanPostProcessor類,可以看到該類完成@Resource @PostConstruct @PreDestroy的解析,如下圖:

static {
		webServiceRefClass = loadAnnotationType("javax.xml.ws.WebServiceRef");
		ejbClass = loadAnnotationType("javax.ejb.EJB");

		resourceAnnotationTypes.add(Resource.class);
		if (webServiceRefClass != null) {
			resourceAnnotationTypes.add(webServiceRefClass);
		}
		if (ejbClass != null) {
			resourceAnnotationTypes.add(ejbClass);
		}
	}
......
 
public CommonAnnotationBeanPostProcessor() {
		setOrder(Ordered.LOWEST_PRECEDENCE - 3);
		setInitAnnotationType(PostConstruct.class);
		setDestroyAnnotationType(PreDestroy.class);
		ignoreResourceType("javax.xml.ws.WebServiceContext");
	}

4. 示例

建立一個BeanDefinitionTest類,實現BeanDefinitionRegistryPostProcessor介面,並在方法中完成設定Bean的型別為BeanClass,然後設定BeanClass物件的username屬性與值,最後註冊到容器中,程式碼如下

@Component
    public class BeanDefinitionTest implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
        genericBeanDefinition.setBeanClass(BeanClass.class);

        MutablePropertyValues propertyValues = genericBeanDefinition.getPropertyValues();
        propertyValues.addPropertyValue("username","wzj");

        registry.registerBeanDefinition("beanClass",genericBeanDefinition);
    }

BeanClass類如下:

@Data
public class BeanClass {

    private String username;
}

測試類如下:

public class TestSpring {

    @Autowired
    private ApplicationContext applicationContext;

    @Test
    public void testComponentScan() {
        applicationContext = new AnnotationConfigApplicationContext("com.wzj");
        BeanClass beanClass = (BeanClass)applicationContext.getBean("beanClass");
        BeanDefinitionTest beanDefinitionTest = (BeanDefinitionTest)applicationContext.getBean("beanDefinitionTest");
        System.out.println("BeanClass-->" + beanClass.getUsername());
        System.out.println("BeanDefinitionTest-->" + beanDefinitionTest.getClass());
    }

程式碼目錄結構如下與執行結果如下

5. 總結

本文以conmponent-scan標籤為例,分析了主要流程,並結合原始碼講述了BeanDefinition屬性的解析、封裝、以及最後註冊到容器中,最後以一個思維導圖總結每個流程中的大致步驟

另外,靜態看原始碼可關注主流程,並做註釋,動態debug示例進入原始碼可直觀感受執行期間的值,原始碼分析不易,搞清楚主流程與思想比原始碼本身更重要。

相關文章