`
frank-liu
  • 浏览: 1682095 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

spring源代码分析:annotation支持的实现

 
阅读更多

简介

    在之前的文章里,我们讨论了spring IOC容器的大致结构和构建bean对象关系网的流程。在那里,bean对象的加载和解析主要是通过纯xml文件解析实现的。但是从spring 2.0以后,对于bean对象的构建和关联可以通过annotation来实现。那么,这一部分的实现细节是怎么样的呢?这就是本文要探讨的重点。 

 

应用示例

    还是老样子,我们先看一个示例,根据这个示例的结果再来讨论引出的问题。我们创建一个普通的工程,它的依赖如下:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.yunzero</groupId>
  <artifactId>componentscansample</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>componentscansample</name>
  <url>http://maven.apache.org</url>

  <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java-version>1.8</java-version>
        <log4j.version>2.10.0</log4j.version>
        <spring.version>5.0.7.RELEASE</spring.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
          
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>${log4j.version}</version>
            <scope>compile</scope>
        </dependency>

        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>${log4j.version}</version>
            <scope>runtime</scope>
        </dependency>
        
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <finalName>${project.artifactId}-${project.version}</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.7.0</version>
                <configuration>
                    <source>${java-version}</source>
                    <target>${java-version}</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

  主要就是添加了对spring的依赖。里面定义有类CustomDAO如下:

 

package com.yunzero.dao;

import org.springframework.stereotype.Component;

@Component
public class CustomerDAO {
	@Override
	public String toString() {
		return "Hello , This is CustomerDAO";
	}	
}

   这部分代码里我们在类的定义前面加了一个Component annotation。然后,我们再定义一个类CustomerService:

 

package com.yunzero.services;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.yunzero.dao.CustomerDAO;

@Component
public class CustomerService {
	@Autowired
	private CustomerDAO customerDAO;
	
	@Override
	public String toString() {
		return "CustomerService [customerDAO=" + customerDAO + "]";
	}
}

    这部分代码里稍微特殊一点的是在于它除了在类定义前添加了Component annotation,里面对成员变量customerDAO也增加了一个Autowired annotation。

    现在,我们再添加一个xml配置文件:

 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.yunzero"/>
</beans>

    它的配置可以说是相当的简单,里面就是说明了一个component-scan的属性。

    现在,我们在主程序里添加如下内容:

 

package com.yunzero;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.yunzero.services.CustomerService;

public class App {
    public static void main( String[] args ) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        
        CustomerService cust = context.getBean(CustomerService.class);
        
        System.out.print(cust);
    }
}

     如果运行程序,将的到如下的输出结果:

 

CustomerService [customerDAO=Hello , This is CustomerDAO]

    和前面一篇文章里介绍的内容不同的地方在于,这里没有在xml文件里定义任何bean。程序里居然可以找到和加载bean对象。为什么会这样呢?在前面的讨论里,我们已经看到了一些不一样的地方了。比如xml文件里component-scan的设置;@Autowired, @Component这些annotation的应用。好像施加了魔法一样,spring居然可以找到需要构建的bean对象。从表面上看来,ComponnentScan指定了base-package信息,那么spring可能通过它在这个指定的范围内查找bean对象的构造信息。而@Component则相当于告诉spring,这就是一个可选的bean对象。而@Autowired则起到一个告诉spring组装bean对象的效果。那么,我们就按照这个猜想往下走。

 

ComponentScan支持

    既然前面猜想到是spring框架识别一些annotation然后做了一些操作。那么,我们就先从spring框架中去寻找一些蛛丝马迹。在前面讨论spring IOC框架基本结构的文章里,我们简单的列了一下它读取配置文件,解析和构造bean关系图的过程。 那里讲到读取和解析文件的流程时,有这么一个顺序图:

 

    这里有一个很关键的类BeanDefinitionDocumentReader,它有一个实现是DefaultBeanDefinitionDocumentReader,里面的registerBeanDefinitions方法就是问题的要点。我们这里先简单的列一下这部分代码:

 

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
	this.readerContext = readerContext;
	logger.debug("Loading bean definitions");
	Element root = doc.getDocumentElement();
	doRegisterBeanDefinitions(root);
}

     这部分代码将真正解析的内容代理到方法doRegisterBeanDefinitions里:

 

protected void doRegisterBeanDefinitions(Element root) {
	// Any nested <beans> elements will cause recursion in this method. In
	// order to propagate and preserve <beans> default-* attributes correctly,
	// keep track of the current (parent) delegate, which may be null. Create
	// the new (child) delegate with a reference to the parent for fallback purposes,
	// then ultimately reset this.delegate back to its original (parent) reference.
	// this behavior emulates a stack of delegates without actually necessitating one.
	BeanDefinitionParserDelegate parent = this.delegate;
	this.delegate = createDelegate(getReaderContext(), root, parent);

	if (this.delegate.isDefaultNamespace(root)) {
		String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
		if (StringUtils.hasText(profileSpec)) {
			String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
					profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
			if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
				if (logger.isInfoEnabled()) {
					logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
							"] not matching: " + getReaderContext().getResource());
				}
				return;
			}
		}
	}
	preProcessXml(root);
	parseBeanDefinitions(root, this.delegate);
	postProcessXml(root);

	this.delegate = parent;
}

     上述的代码主要是用来解析xml文件里<beans>里面的内容。相当于在一个文件里定义的一个个bean对象了。详细的实现在parseBeanDefinitions里:

 

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
	if (delegate.isDefaultNamespace(root)) {
		NodeList nl = root.getChildNodes();
		for (int i = 0; i < nl.getLength(); i++) {
			Node node = nl.item(i);
			if (node instanceof Element) {
				Element ele = (Element) node;
				if (delegate.isDefaultNamespace(ele)) {
					parseDefaultElement(ele, delegate);
				}
				else {
					delegate.parseCustomElement(ele);
				}
			}
		}
	}
	else {
		delegate.parseCustomElement(root);
	}
}

    在之前的文章里我们对这段代码的一个分支进行了分析。里面的parseDefaultElement方法就开始解析里面具体的<bean>结构对象了。但是这里还有另外一个分支,就是delegate.parseCustomElement。在判断出当前节点的默认元素是否属于当前默认的namespace之后,它会调用这个方法。因为在程序里,默认的是beans的namespace,它的定义是:

http://www.springframework.org/schema/beans

   而前面的示例里我们可以看到,像component-scan,它的前面是有context修饰的,说明它的默认namespace是在context里,context namespace的定义是:

 

http://www.springframework.org/schema/context

    我们再跟进去看看parseCustomElement方法的实现:

 

@Nullable
public BeanDefinition parseCustomElement(Element ele) {
	return parseCustomElement(ele, null);
}

@Nullable
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
	String namespaceUri = getNamespaceURI(ele);
	if (namespaceUri == null) {
		return null;
	}
	NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
	if (handler == null) {
		error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
		return null;
	}
	return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}

    到这里,我们会发现实际的解析工作还是进一步代理给一个NamespaceHandler的对象了。而这个具体的parse方法是在NamespaceHandler的一个子类里实现的,也就是NamespaceHandlerSupport:

 

public BeanDefinition parse(Element element, ParserContext parserContext) {
	BeanDefinitionParser parser = findParserForElement(element, parserContext);
	return (parser != null ? parser.parse(element, parserContext) : null);
}

@Nullable
private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
	String localName = parserContext.getDelegate().getLocalName(element);
	BeanDefinitionParser parser = this.parsers.get(localName);
	if (parser == null) {
		parserContext.getReaderContext().fatal(
				"Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
	}
	return parser;
}

     绕了半天,原来这里最终是通过一个从它本地的一个HashMap类型的parsers里获取到的一个parser来处理的。那么,这些parser是怎么注册到里面去的呢?我们怎么找到合适的parser呢?这部分先搁置一下,我们后面会讨论。

    从代码里看到的,它返回的是一个BeanDefinitionParser的接口,在它的实际实现里有一个类ComponentScanBeanDefinitionParser。它的实现里就是对这部分的具体解析了:

 

public BeanDefinition parse(Element element, ParserContext parserContext) {
	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);
	registerComponents(parserContext.getReaderContext(), beanDefinitions, element);

	return null;
}

    这方法里前面部分是解析里面的"base-package"部分,然后得到一组设定的包名,它是一个数组。然后通过configureScanner方法来设置一个scanner对象,再由它来进行进一步的扫描工作。所以,最终的的扫描包的职责就由这个scanner对象来做了。我们先来看看configureScanner方法:

 

protected ClassPathBeanDefinitionScanner configureScanner(ParserContext parserContext, Element element) {
	boolean useDefaultFilters = true;
	if (element.hasAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE)) {
		useDefaultFilters = Boolean.valueOf(element.getAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE));
	}

	// Delegate bean definition registration to scanner class.
	ClassPathBeanDefinitionScanner scanner = createScanner(parserContext.getReaderContext(), useDefaultFilters);
		scanner.setBeanDefinitionDefaults(parserContext.getDelegate().getBeanDefinitionDefaults());
		scanner.setAutowireCandidatePatterns(parserContext.getDelegate().getAutowireCandidatePatterns());

	if (element.hasAttribute(RESOURCE_PATTERN_ATTRIBUTE)) {
		scanner.setResourcePattern(element.getAttribute(RESOURCE_PATTERN_ATTRIBUTE));
	}

	try {
		parseBeanNameGenerator(element, scanner);
	}
	catch (Exception ex) {
		parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause());
	}

	try {
		parseScope(element, scanner);
	}
	catch (Exception ex) {
		parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause());
	}

	parseTypeFilters(element, scanner, parserContext);

	return scanner;
}

     这段代码里,前面的部分只是创建一个ClassPathBeanDefinitionScanner。然后的parseBeanNameGenerator方法解析文件里“name-generator”的配置项,如果有的话,则配置相应的BeanNameGenerator。后面的parseScope方法则是解析配置文件中有“scope-resolver”,"scoped-proxy"等项时的配置解析工作。后面的parseTypeFilters方法则是解析文件里如果含有"include-filter", "exclude-filter"等配置项时的工作。看这部分的时候,可能会有点迷糊,为什么要解析这么多有的没的?因为这些都是@ComponentScan里的配置项,我们只要看看这个annotation里的定义就明白了。

 

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
	@AliasFor("basePackages")
	String[] value() default {};

	@AliasFor("value")
	String[] basePackages() default {};

	Class<?>[] basePackageClasses() default {};

	Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

	Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;

	ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;

	String resourcePattern() default ClassPathScanningCandidateComponentProvider.DEFAULT_RESOURCE_PATTERN;

	boolean useDefaultFilters() default true;

	Filter[] includeFilters() default {};

	Filter[] excludeFilters() default {};

	boolean lazyInit() default false;

	@Retention(RetentionPolicy.RUNTIME)
	@Target({})
	@interface Filter {
		FilterType type() default FilterType.ANNOTATION;

		@AliasFor("classes")
		Class<?>[] value() default {};

		@AliasFor("value")
		Class<?>[] classes() default {};

		String[] pattern() default {};

	}

}

    从ComponentScan annotation的定义里就可以看到,它包含有"base-packages", "nameGenerator", "scopedProxy"等属性,所以前面的那些代码就是对它们的解析。

    总的来说,这部分代码中规中矩,没什么特殊的。我们接着看看scanner.doScan方法:

 

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) {
		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) {
				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;
}

     这部分代码里,主要的逻辑就是通过findCandidateComponents方法来找到候选的组件。这个方法的实现细节我们会接着跟进。第6行的for循环里,针对每个BeanDefinition进行解析处理,比如获取它的scope信息,设置它的scope信息和生成beanName等信息。

    我们接着来看findCandidateComponents方法,它定义在类ClassPathScanningCandidateComponentProvider里:

 

public Set<BeanDefinition> findCandidateComponents(String basePackage) {
	if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
		return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
	}
	else {
		return scanCandidateComponents(basePackage);
	}
}

    在这个方法里,第一个判断条件是如果componentsIndex不为空而且indexSupportsIncludeFilters时,走addCandidateComponentsForIndex方法的流程,否则走scanCandidateComponents方法的流程。其中addCandidateComponentsForIndex的流程实现如下:

 

private Set<BeanDefinition> addCandidateComponentsFromIndex(CandidateComponentsIndex index, String basePackage) {
	Set<BeanDefinition> candidates = new LinkedHashSet<>();
	try {
		Set<String> types = new HashSet<>();
		for (TypeFilter filter : this.includeFilters) {
			String stereotype = extractStereotype(filter);
			if (stereotype == null) {
				throw new IllegalArgumentException("Failed to extract stereotype from "+ filter);
			}
			types.addAll(index.getCandidateTypes(basePackage, stereotype));
		}
		boolean traceEnabled = logger.isTraceEnabled();
		boolean debugEnabled = logger.isDebugEnabled();
		for (String type : types) {
			MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(type);
			if (isCandidateComponent(metadataReader)) {
				AnnotatedGenericBeanDefinition sbd = new AnnotatedGenericBeanDefinition(
						metadataReader.getAnnotationMetadata());
				if (isCandidateComponent(sbd)) {
					if (debugEnabled) {
						logger.debug("Using candidate component class from index: " + type);
					}
					candidates.add(sbd);
				}
				else {
					if (debugEnabled) {
						logger.debug("Ignored because not a concrete top-level class: " + type);
					}
				}
			}
			else {
				if (traceEnabled) {
					logger.trace("Ignored because matching an exclude filter: " + type);
				}
			}
		}
	}
	catch (IOException ex) {
		throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
	}
	return candidates;
}

     上述代码的第5到第10行主要是通过CandidateComponentsIndex的getCandidateTypes方法来获取备选的类型信息。这里获取到的是备选的类型字符串信息。其中getCandidateTypes方法的实现如下:

 

public Set<String> getCandidateTypes(String basePackage, String stereotype) {
	List<Entry> candidates = this.index.get(stereotype);
	if (candidates != null) {
		return candidates.parallelStream()
				.filter(t -> t.match(basePackage))
				.map(t -> t.type)
				.collect(Collectors.toSet());
	}
	return Collections.emptySet();
}

       这个方法里通过index这个Map<K, List<V>>的数据类型获取到给定类型原型信息的一组Entry。然后根据它的包名是否匹配来返回符合的类型集合。

   我们接着前面addCandidateComponentsFromIndex方法来看。第15行开始的for循环里主要做的事就是通过给定的type String信息,找到对应的MetadataReader,并用它来尝试解析获取到的元数据信息。里面getMetadataReader方法会根据传入的type String去找到它对应于classpath的resource信息。这里的resource信息正好和我们之前文章里讨论的Resource接口对应上了。在它的底层实现里,它使用了ClassLoader来尝试加载设定好的类。然后,再通过metadataReader.getAnnotationMetadata来获取到对应的BeanDefinition信息。如果这个beanDefinition对象是候选的component,则加入到candidates集合里。

    另外一种扫描component的路径则在前面提到的方法scanCandidateComponents里:

 

private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
	Set<BeanDefinition> candidates = new LinkedHashSet<>();
	try {
		String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
				resolveBasePackage(basePackage) + '/' + this.resourcePattern;
		Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
		boolean traceEnabled = logger.isTraceEnabled();
		boolean debugEnabled = logger.isDebugEnabled();
		for (Resource resource : resources) {
			if (traceEnabled) {
				logger.trace("Scanning " + resource);
			}
			if (resource.isReadable()) {
				try {
					MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
					if (isCandidateComponent(metadataReader)) {
						ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
						sbd.setResource(resource);
						sbd.setSource(resource);
						if (isCandidateComponent(sbd)) {
							if (debugEnabled) {
								logger.debug("Identified candidate component class: " + resource);
							}
							candidates.add(sbd);
						}
						else {
							if (debugEnabled) {
								logger.debug("Ignored because not a concrete top-level class: " + resource);
							}
						}
					}
					else {
						if (traceEnabled) {
							logger.trace("Ignored because not matching any filter: " + resource);
						}
					}
				}
				catch (Throwable ex) {
					throw new BeanDefinitionStoreException(
							"Failed to read candidate component class: " + resource, ex);
				}
			}
			else {
				if (traceEnabled) {
					logger.trace("Ignored because not readable: " + resource);
				}
			}
		}
	}
	catch (IOException ex) {
		throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
	}
	return candidates;
}

     这部分代码算是系统实现里面比较核心的部分。我们仔细的看过来。其中第4行的代码用来拼凑包搜索的路径,它将包名中的.符号替换成/符号。这样相当于构成了一个路径的结构。这样,假如我们要扫描一个com.abc这样的包,它将被组装成classpath*:com/abc/**/*.class这样的一个字符串。第6行的代码则是解析这个路径来获得对应的Resource。这个获取对应Resource的过程在类PathMatchingResourcePatternResolver的getResources方法里:

 

public Resource[] getResources(String locationPattern) throws IOException {
	Assert.notNull(locationPattern, "Location pattern must not be null");
	if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {
		// a class path resource (multiple resources for same name possible)
		if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {
			// a class path resource pattern
			return findPathMatchingResources(locationPattern);
		}
		else {
			// all class path resources with the given name
			return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));
		}
	}
	else {
		// Generally only look for a pattern after a prefix here,
		// and on Tomcat only after the "*/" separator for its "war:" protocol.
		int prefixEnd = (locationPattern.startsWith("war:") ? locationPattern.indexOf("*/") + 1 :
				locationPattern.indexOf(':') + 1);
		if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {
			// a file pattern
			return findPathMatchingResources(locationPattern);
		}
		else {
			// a single resource with the given name
			return new Resource[] {getResourceLoader().getResource(locationPattern)};
		}
	}
}

    这部分代码里,首先会判断传入的路径字符串是否以classpath*:开头,如果是的,则走第5行判断后面的字符串是否包含有*或者?这些通配符。如果包含这些的话,表示这里是匹配的多个resource,接着会调用findPathMatchingResources这个方法。否则会调用findAllClassPathResources这个方法。这两个方法我们接着会详细看。在第14行的else条件里,表示传入的路径并没有包含classpath*:的开头。在后面也是判断,在给定的前缀字符串war:协议或者*/之后是否包含有多个resource,如果是的话,调用findPathMatchingResources这个方法。否则表示指定的是一个单一的resource,可以直接初始化它。

    我们先来看看findPathMatchingResources的实现:

 

protected Resource[] findPathMatchingResources(String locationPattern) throws IOException {
	String rootDirPath = determineRootDir(locationPattern);
	String subPattern = locationPattern.substring(rootDirPath.length());
	Resource[] rootDirResources = getResources(rootDirPath);
	Set<Resource> result = new LinkedHashSet<>(16);
	for (Resource rootDirResource : rootDirResources) {
		rootDirResource = resolveRootDirResource(rootDirResource);
		URL rootDirUrl = rootDirResource.getURL();
		if (equinoxResolveMethod != null && rootDirUrl.getProtocol().startsWith("bundle")) {
			URL resolvedUrl = (URL) ReflectionUtils.invokeMethod(equinoxResolveMethod, null, rootDirUrl);
			if (resolvedUrl != null) {
				rootDirUrl = resolvedUrl;
			}
			rootDirResource = new UrlResource(rootDirUrl);
		}
		if (rootDirUrl.getProtocol().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) {
			result.addAll(VfsResourceMatchingDelegate.findMatchingResources(rootDirUrl, subPattern, getPathMatcher()));
		}
		else if (ResourceUtils.isJarURL(rootDirUrl) || isJarResource(rootDirResource)) {
			result.addAll(doFindPathMatchingJarResources(rootDirResource, rootDirUrl, subPattern));
		}
		else {
			result.addAll(doFindPathMatchingFileResources(rootDirResource, subPattern));
		}
	}
	if (logger.isDebugEnabled()) {
		logger.debug("Resolved location pattern [" + locationPattern + "] to resources " + result);
	}
	return result.toArray(new Resource[0]);
}

     这一段代码看起来有一个比较容易让人困惑的地方,就是这里递归的调用了getResources方法。在determineRootDir方法中会截取最后一个'/'符号前的串作为resource的根目录。结合前面getResources方法的细节来看,它第4行的代码里会判断截取了"classpath*:"之后的字符串是否还有*,?等通配符。如果没有的话,则会进入到findAllClassPathResources方法里了。而里面如果还有这些通配符才会继续这个方法进行进一步的解析。第6行开始的代码则是在得到了所有的Resource之后解析各种协议下的Resource,比如bundle, jar, vfs以及普通文件。最后返回实现Resource接口的特定Resource对象。比如说基于文件的Resource, 它就是通过扫描给定的path,然后将符合条件的文件构造成FileSystemResource对象。其他协议的也类似。

    现在,我们接着来看findAllClassPathResources。前面递归的形式里最终还是要走到这个方法里来:

 

protected Resource[] findAllClassPathResources(String location) throws IOException {
	String path = location;
	if (path.startsWith("/")) {
		path = path.substring(1);
	}
	Set<Resource> result = doFindAllClassPathResources(path);
	if (logger.isDebugEnabled()) {
		logger.debug("Resolved classpath location [" + location + "] to resources " + result);
	}
	return result.toArray(new Resource[0]);
}

    这部分代码主要还是委托doFinadAllClassPathResources方法来做。 

 

protected Set<Resource> doFindAllClassPathResources(String path) throws IOException {
	Set<Resource> result = new LinkedHashSet<>(16);
	ClassLoader cl = getClassLoader();
	Enumeration<URL> resourceUrls = (cl != null ? cl.getResources(path) : ClassLoader.getSystemResources(path));
	while (resourceUrls.hasMoreElements()) {
		URL url = resourceUrls.nextElement();
		result.add(convertClassLoaderURL(url));
	}
	if ("".equals(path)) {
		// The above result is likely to be incomplete, i.e. only containing file system references.
		// We need to have pointers to each of the jar files on the classpath as well...
		addAllClassLoaderJarRoots(cl, result);
	}
	return result;
}

     很显然,这里其实是通过classloader来加载所有的resource。只是这里的resource是URL的类型,然后需要转换成Resource对象。在这里,第9行的方法则是用来处理如果传入的路径为空字符串,则说明这个传入的文件可能在系统classpath所在的某个jar包里。这里就需要根据addAllClassLoaderJarRoots方法来进一步解析jar包的内容了。显然,到这一步的时候,大部分加载resource的流程就走完了。概括起来说就是最终通过classloader找到了这些指定base-package的资源并加载进来。

    上述过程中牵涉到的类关系如下图:

     从图中比较容易看到它们更多的是一种依赖的关系。而且,在前面的讨论里已经看到,它本身的实现细节就是通过代理关系来实现的。在知道牵涉到的类和对象之后,我们再针对前面的调用过程稍微总结一下。它的整体顺序图如下: 

    从最开始的DefaultBeanDefinitionDocumentReader,到BeanDefinitionParserDelegate一直到最后的ClassLoader。它们基本上就是这么一路代理的过程下来的。在跟踪代码的过程中会显得很痛苦。

 

其他annotation的解析流程

AnnotationConfigApplicationContext

    除了我们上述讨论的一个流程中对@ComponentScan的支持,在spring本身对annotation的支持上,我们也有一些专门的类来做相关的工作。这个就是AnnotationConfigApplicationContext。它本身的逻辑并不复杂,在理解了前面的流程之后,相对就好很多了。

   在它本身的定义里有两个成员变量:

 

private final AnnotatedBeanDefinitionReader reader;

private final ClassPathBeanDefinitionScanner scanner;

    在它的功能里,提供了两种基于annotation查找bean的方法。一种方法的定义如下:

 

public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
	this();
	register(annotatedClasses);
	refresh();
}

    这种方式是通过提供一些特定的class,然后通过register方法来注册bean。这里的关键点在于register方法,在通过这个方法注册完bean之后,再调用refresh方法来执行其他的操作。而在前面的文章里我们已经知道,refresh方法是整个流程的最关键点。

 

    还有另外一种方法是scan,这个和前面的@ComponentScan类似,我们指定basePackages,然后去扫描指定目录下的class。它所在的构造函数方法如下:

 

public AnnotationConfigApplicationContext(String... basePackages) {
	this();
	scan(basePackages);
	refresh();
}

 

    我们接着深入看看register方法和scan方法的实现。

 

public void register(Class<?>... annotatedClasses) {
	Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
	this.reader.register(annotatedClasses);
}

public void register(Class<?>... annotatedClasses) {
	for (Class<?> annotatedClass : annotatedClasses) {
		registerBean(annotatedClass);
	}
}

     在register方法里,它的详细实现细节是通过AnnotatedBeanDefinitionReader实现的。里面真正关键的实现在方法registerBean里:

 

<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
		@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {

	AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
	if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
		return;
	}

	abd.setInstanceSupplier(instanceSupplier);
	ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
	abd.setScope(scopeMetadata.getScopeName());
	String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

	AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
	if (qualifiers != null) {
		for (Class<? extends Annotation> qualifier : qualifiers) {
			if (Primary.class == qualifier) {
				abd.setPrimary(true);
			}
			else if (Lazy.class == qualifier) {
				abd.setLazyInit(true);
			}
			else {
				abd.addQualifier(new AutowireCandidateQualifier(qualifier));
			}
		}
	}
	for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
		customizer.customize(abd);
	}
	BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
	definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
	BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}

     上述代码第10行主要解析AnnotatedGenericBeanDefinition里的scope metadata。因为是通过Annotation修饰的bean对象,我们可能在Annotation里指定了它的scope信息,所以这部分就是做这个的。

    第12行代码主要通过beanGenerator来生成一个唯一的名字,保证名字不会有冲突。

    第14行代码的processCommonDefinitionAnnotations方法主要处理BeanDefinition里定义的Lazy, Primary, DependsOn, Description等元数据信息的。这些和xml文件定义的内容相似,无非就是解析的方式有点不一样。

    第15到第27行主要是用来处理传入的qualifier参数的。这些传入的qualiier都是一些Annotation class。

    第28到30行则是用来处理传入的definitionCustomizers参数。如果有一些自定义的对beanDefinition的处理,可以在这里传入它的实现。

    剩下的代码则是通过BeanDefinitionReaderUtils里的registerBeanDefinition方法来将解析后的BeanDefinitionHolder注册到registry里。这样,在后续使用的时候,我们可以直接访问到这些bean了。这里针对registerBeanDefinition再多说一句。我们通过BeanDefinitionRegistry来注册的BeanDefinition最终是保存在一个类型为Map<String, BeanDefinition>的map里。倒也没什么特别稀奇的东西。

    现在我们再来看看scan方法的实现。既然这里就是指定basePackages,然后去查找里面的candidates,有了之前的分析,我们可以猜想,他们的最终实现应该是一样的。scan方法的实现如下,在ClassPathBeanDefinitionScanner里:

public int scan(String... basePackages) {
	int beanCountAtScanStart = this.registry.getBeanDefinitionCount();

	doScan(basePackages);

	// Register annotation config processors, if necessary.
	if (this.includeAnnotationConfig) {
		AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
	}

	return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}

    上面代码里的doScan方法正好就是我们前面讨论分析过的流程里的一部分。这样,这部分其实就合并到前面的流程里了。基本上没什么区别。最终还是通过classloader来加载resource。还有一个值得分析一下的就是后面第7行里的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<>(4);

	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));
	}

	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));
	}

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

	// Check for JSR-250 support, and if present add the 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;
}

     这部分的代码看起来比较长,他其实主要做的事情就是注册各种postProcessor。里面四个主要的就是CommonAnnotationBeanPostProcessor, RequiredAnnotationBeanPostProcessor, AutowiredAnnotationBeanPostProcessor, ConfigurationClassPostProcessor。通过这几个processor的实现分析,我们前面扫描之后的到的resource是怎么识别成bean对象以及是怎么组合在一起的就很明白了。我们针对它们每个实现都详细了解一下。

 

CommonAnnotationBeanPostProcessor

    这个beanPostProcessor主要用来处理一些比较常用的annotation。像@PostConstructor, @PreDestroy, @Resource还有web service相关的@WebServiceRef, @EJB这些的支持实现都在这里。它相关的类结构图如下: 

    它的初始化和销毁对象的定义继承自InitDestroyAnnotationBeanPostProcessor。它的构造函数和初始化对象的实现如下:

 

//WebService关于JAX-WS的相关注解  
private static Class<? extends Annotation> webServiceRefClass = null;  
//EJB相关的注解  
private static Class<? extends Annotation> ejbRefClass = null;  
    
//静态初始化块  
static {  
    //获取当前类的类加载器  
    ClassLoader cl = CommonAnnotationBeanPostProcessor.class.getClassLoader();  
    try {  
        //使用类加载器加载WebService相关的类  
        webServiceRefClass = (Class) cl.loadClass("javax.xml.ws.WebServiceRef");  
    }  
    catch (ClassNotFoundException ex) {  
        webServiceRefClass = null;  
    }  
    try {  
        //使用类加载器加载EJB相关的类  
        ejbRefClass = (Class) cl.loadClass("javax.ejb.EJB");  
    }  
    catch (ClassNotFoundException ex) {  
        ejbRefClass = null;  
    }  
}   
//构造方法  
public CommonAnnotationBeanPostProcessor() {  
    setOrder(Ordered.LOWEST_PRECEDENCE - 3);  
    //设置初始的注解类型为@PostConstruct  
    setInitAnnotationType(PostConstruct.class);  
    //设置消耗的注解为@ PreDestroy  
    setDestroyAnnotationType(PreDestroy.class);  
    //当使用@Resource注解时,忽略JAX-WS的资源类型  
    ignoreResourceType("javax.xml.ws.WebServiceContext");  
}  

    这里比较重要的代码是对属性的处理部分,它的详细实现如下:

 

@Override
public PropertyValues postProcessPropertyValues(
		PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {

	InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
	try {
		metadata.inject(bean, beanName, pvs);
	}
	catch (Throwable ex) {
		throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
	}
	return pvs;
}


private InjectionMetadata findResourceMetadata(String beanName, final Class<?> clazz, @Nullable PropertyValues pvs) {
	// Fall back to class name as cache key, for backwards compatibility with custom callers.
	String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
	// Quick check on the concurrent map first, with minimal locking.
	InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
	if (InjectionMetadata.needsRefresh(metadata, clazz)) {
		synchronized (this.injectionMetadataCache) {
			metadata = this.injectionMetadataCache.get(cacheKey);
			if (InjectionMetadata.needsRefresh(metadata, clazz)) {
				if (metadata != null) {
					metadata.clear(pvs);
				}
				metadata = buildResourceMetadata(clazz);
				this.injectionMetadataCache.put(cacheKey, metadata);
			}
		}
	}
	return metadata;
}

private InjectionMetadata buildResourceMetadata(final Class<?> clazz) {
	LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<>();
	Class<?> targetClass = clazz;

	do {
		final LinkedList<InjectionMetadata.InjectedElement> currElements =
				new LinkedList<>();

		ReflectionUtils.doWithLocalFields(targetClass, field -> {
			if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) {
				if (Modifier.isStatic(field.getModifiers())) {
					throw new IllegalStateException("@WebServiceRef annotation is not supported on static fields");
				}
				currElements.add(new WebServiceRefElement(field, field, null));
			}
			else if (ejbRefClass != null && field.isAnnotationPresent(ejbRefClass)) {
				if (Modifier.isStatic(field.getModifiers())) {
					throw new IllegalStateException("@EJB annotation is not supported on static fields");
				}
				currElements.add(new EjbRefElement(field, field, null));
			}
			else if (field.isAnnotationPresent(Resource.class)) {
				if (Modifier.isStatic(field.getModifiers())) {
					throw new IllegalStateException("@Resource annotation is not supported on static fields");
				}
				if (!ignoredResourceTypes.contains(field.getType().getName())) {
					currElements.add(new ResourceElement(field, field, null));
				}
			}
		});

		ReflectionUtils.doWithLocalMethods(targetClass, method -> {
			Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
			if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
				return;
			}
			if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
				if (webServiceRefClass != null && bridgedMethod.isAnnotationPresent(webServiceRefClass)) {
					if (Modifier.isStatic(method.getModifiers())) {
						throw new IllegalStateException("@WebServiceRef annotation is not supported on static methods");
					}
					if (method.getParameterCount() != 1) {
						throw new IllegalStateException("@WebServiceRef annotation requires a single-arg method: " + method);
					}
					PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
					currElements.add(new WebServiceRefElement(method, bridgedMethod, pd));
				}
				else if (ejbRefClass != null && bridgedMethod.isAnnotationPresent(ejbRefClass)) {
					if (Modifier.isStatic(method.getModifiers())) {
						throw new IllegalStateException("@EJB annotation is not supported on static methods");
					}
					if (method.getParameterCount() != 1) {
						throw new IllegalStateException("@EJB annotation requires a single-arg method: " + method);
					}
					PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
					currElements.add(new EjbRefElement(method, bridgedMethod, pd));
				}
				else if (bridgedMethod.isAnnotationPresent(Resource.class)) {
					if (Modifier.isStatic(method.getModifiers())) {
						throw new IllegalStateException("@Resource annotation is not supported on static methods");
					}
					Class<?>[] paramTypes = method.getParameterTypes();
					if (paramTypes.length != 1) {
						throw new IllegalStateException("@Resource annotation requires a single-arg method: " + method);
					}
					if (!ignoredResourceTypes.contains(paramTypes[0].getName())) {
						PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
						currElements.add(new ResourceElement(method, bridgedMethod, pd));
					}
				}
			}
		});

		elements.addAll(0, currElements);
		targetClass = targetClass.getSuperclass();
	}
	while (targetClass != null && targetClass != Object.class);

	return new InjectionMetadata(clazz, elements);
}

     上述这个过程看起来比较长,主要是通过findResourceMetadata和buildResourceMetadata来查找对应的元数据。它的处理过程和AutowiredAnnotationBeanPostProcessor的过程基本一样。除了查找属性值的过程不一样。AutowiredAnnotationBeanPostProcessor主要通过解析里面的required配置来获取依赖的属性值,这里则通过解析@Resource属性来获取相关信息。

    在findResourceMetadata方法里,首先通过查找injectionMetadataCache来查找对应的属性是否在缓存里,如果有就直接返回了。否则针对这个缓存加同步块,并重新构建针对给定key的metadata。

    这些方法里,重点就是buildResourceMetadata。它主要由两个doWithLocalFields方法组成,第一个方法判断当前的field是webServiceRefClass, ejbRefClass或者Resource class。如果是上述的某一种,就构造对应类型的Element对象。这里有WebServiceRefElement, EjbRefElement, ResourceElement等几种,它们都是最终继承的InjectionMetadata.InjectedElement。接着的第二个doWithLocalFields方法主要针对方法来查找对应的注解。它也是类似的查找当前的方法是否被webServiceRefClass, ejbRefClass或者Resource class修饰,如果是的话,则构建对应的Element对象。最后将这些数据收集起来构造InjectionMetadata对象。上述代码中有一个细节就是对于方法上面的注解,EJB和WebService相关注解以及@Resource只能在单个参数的方法上配置,否则会有异常抛出。

    代码里还有一个比较重要的部分,就是根据给定名称或者类型获取资源对象。它的实现在getResource方法里。它的实现被WebService, Ejb, Resource三种Element的实现给调用。详细的实现如下:

 

protected Object getResource(LookupElement element, @Nullable String requestingBeanName) throws BeansException {
	if (StringUtils.hasLength(element.mappedName)) {
		return this.jndiFactory.getBean(element.mappedName, element.lookupType);
	}
	if (this.alwaysUseJndiLookup) {
		return this.jndiFactory.getBean(element.name, element.lookupType);
	}
	if (this.resourceFactory == null) {
		throw new NoSuchBeanDefinitionException(element.lookupType,
				"No resource factory configured - specify the 'resourceFactory' property");
	}
	return autowireResource(this.resourceFactory, element, requestingBeanName);
}


protected Object autowireResource(BeanFactory factory, LookupElement element, @Nullable String requestingBeanName)
	throws BeansException {

	Object resource;
	Set<String> autowiredBeanNames;
	String name = element.name;

	if (this.fallbackToDefaultTypeMatch && element.isDefaultName &&
			factory instanceof AutowireCapableBeanFactory && !factory.containsBean(name)) {
		autowiredBeanNames = new LinkedHashSet<>();
		resource = ((AutowireCapableBeanFactory) factory).resolveDependency(
				element.getDependencyDescriptor(), requestingBeanName, autowiredBeanNames, null);
		if (resource == null) {
			throw new NoSuchBeanDefinitionException(element.getLookupType(), "No resolvable resource object");
		}
	}
	else {
		resource = factory.getBean(name, element.lookupType);
		autowiredBeanNames = Collections.singleton(name);
	}

	if (factory instanceof ConfigurableBeanFactory) {
		ConfigurableBeanFactory beanFactory = (ConfigurableBeanFactory) factory;
		for (String autowiredBeanName : autowiredBeanNames) {
			if (requestingBeanName != null && beanFactory.containsBean(autowiredBeanName)) {
				beanFactory.registerDependentBean(autowiredBeanName, requestingBeanName);
			}
		}
	}

	return resource;
}

    在getResource方法里,它会首先去判断当前的element对象,如果有映射的名字,会尝试用jndiFactory来获取bean对象,否则尝试resourceFactory。使用resourceFactory的话,会通过autowireResource方法来最终获取到需要的bean对象。

   autowireResource的实现相对比较直接,首先判断如果是通过类型匹配来查找bean对象的话,它通过对应的beanFactory来解析给定的依赖关系,将依赖直接返回。如果不是则通过factory来查找这个对象。对于特定的ConfigurableBeanFactory,还需要注册依赖的bean。

 

 

RequiredAnnotationBeanPostProcessor

 

 

 

 

public PropertyValues postProcessPropertyValues(
		PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
         //如果容器缓存中没有指定Bean名称  
	if (!this.validatedBeanNames.contains(beanName)) {
                //如果指定Bean定义中没有设置skipRequiredCheck属性  
		if (!shouldSkip(this.beanFactory, beanName)) {
			List<String> invalidProperties = new ArrayList<>();
			for (PropertyDescriptor pd : pds) {
                                //如果属性添加了@Required注解,且属性集合中不包含指定名称的属性  
				if (isRequiredProperty(pd) && !pvs.contains(pd.getName())) {
                                        //当前属性为无效的属性
					invalidProperties.add(pd.getName());
				}
			}
			if (!invalidProperties.isEmpty()) {
				throw new BeanInitializationException(buildExceptionMessage(invalidProperties, beanName));
			}
		}
                //将Bean名称缓存到容器中 
		this.validatedBeanNames.add(beanName);
	}
        //返回经过验证的属性值
	return pvs;
}

protected boolean isRequiredProperty(PropertyDescriptor propertyDescriptor) {
        //获取给定属性的写方法(setter方法)  
	Method setter = propertyDescriptor.getWriteMethod();
        //检查给定属性方法上是否存在指定类型的注解
	return (setter != null && AnnotationUtils.getAnnotation(setter, getRequiredAnnotationType()) != null);
}

protected boolean shouldSkip(@Nullable ConfigurableListableBeanFactory beanFactory, String beanName) {
	if (beanFactory == null || !beanFactory.containsBeanDefinition(beanName)) {
		return false;
	}
	BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
	if (beanDefinition.getFactoryBeanName() != null) {
		return true;
	}
	Object value = beanDefinition.getAttribute(SKIP_REQUIRED_CHECK_ATTRIBUTE);
	return (value != null && (Boolean.TRUE.equals(value) || Boolean.valueOf(value.toString())));
}

 

 

 

AutowiredAnnotationBeanPostProcessor

   这个postProcessor就是用来处理@Autowired, @Value, @Inject这几个主要的annotation的。其中@Inject是JSR-330里的标准annotation。在看它的详细实现之前,我们可以看一下它要处理的@Autowired的详细定义: 

 

@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
	boolean required() default true;

}

     在这个详细的定义里,我们可以看到它可以被用到构造函数、方法、传递的参数,声明的字段以及annotation上。所以,在实现的时候,我们可以猜想一下,这里会有相关的方法针对这几个方面进行处理。

    AutowiredAnnotationBeanPostProcessor相关的类结构图如下:

    在这个图里可以看到,它实现了BeanPostProcessor, Ordered, Aware等几个接口。而里面最重要的就是BeanPostProcessor里的方法。正是因为通过这里的方法,它可以对前面定义的bean对象做一些进一步的处理。我们现在对里面的一些实现细节了解一下。

    它本身的构造函数如下:

    

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.info("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
	}
	catch (ClassNotFoundException ex) {
		// JSR-330 API not available - simply skip.
	}
}

    这部分代码一开始就对它需要处理的annotation type做一个整理。首先,Autowired, Value两个class是必须要处理的。而如果能找到javax.inject.Inject 类的话,它也要被加进来进行处理,否则就忽略它。

   

public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName)
		throws BeanCreationException {

	// Let's check for lookup methods here..
	if (!this.lookupMethodsChecked.contains(beanName)) {
		try {
			ReflectionUtils.doWithMethods(beanClass, method -> {
				Lookup lookup = method.getAnnotation(Lookup.class);
				if (lookup != null) {
					Assert.state(beanFactory != null, "No BeanFactory available");
					LookupOverride override = new LookupOverride(method, lookup.value());
					try {
						RootBeanDefinition mbd = (RootBeanDefinition) beanFactory.getMergedBeanDefinition(beanName);
						mbd.getMethodOverrides().addOverride(override);
					}
					catch (NoSuchBeanDefinitionException ex) {
						throw new BeanCreationException(beanName,
							"Cannot apply @Lookup to beans without corresponding bean definition");
					}
				}
			});
		}
		catch (IllegalStateException ex) {
			throw new BeanCreationException(beanName, "Lookup method resolution failed", ex);
		}
		this.lookupMethodsChecked.add(beanName);
	}

	// Quick check on the concurrent map first, with minimal locking.
	Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass);
	if (candidateConstructors == null) {
		// Fully synchronized resolution now...
		synchronized (this.candidateConstructorsCache) {
			candidateConstructors = this.candidateConstructorsCache.get(beanClass);
			if (candidateConstructors == null) {
				Constructor<?>[] rawCandidates;
				try {
					rawCandidates = beanClass.getDeclaredConstructors();
				}
				catch (Throwable ex) {
					throw new BeanCreationException(beanName,
							"Resolution of declared constructors on bean Class [" + beanClass.getName() +
							"] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
				}
				List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length);
				Constructor<?> requiredConstructor = null;
				Constructor<?> defaultConstructor = null;
				Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass);
				int nonSyntheticConstructors = 0;
				for (Constructor<?> candidate : rawCandidates) {
					if (!candidate.isSynthetic()) {
						nonSyntheticConstructors++;
					}
					else if (primaryConstructor != null) {
						continue;
					}
					AnnotationAttributes ann = findAutowiredAnnotation(candidate);
					if (ann == null) {
						Class<?> userClass = ClassUtils.getUserClass(beanClass);
						if (userClass != beanClass) {
							try {
								Constructor<?> superCtor =
							userClass.getDeclaredConstructor(candidate.getParameterTypes());
								ann = findAutowiredAnnotation(superCtor);
							}
							catch (NoSuchMethodException ex) {
								// Simply proceed, no equivalent superclass constructor found...
							}
						}
					}
					if (ann != null) {
						if (requiredConstructor != null) {
							throw new BeanCreationException(beanName,
									"Invalid autowire-marked constructor: " + candidate +
									". Found constructor with 'required' Autowired annotation already: " +
									requiredConstructor);
						}
						boolean required = determineRequiredStatus(ann);
						if (required) {
							if (!candidates.isEmpty()) {
								throw new BeanCreationException(beanName,
										"Invalid autowire-marked constructors: " + candidates +
										". Found constructor with 'required' Autowired annotation: " +
										candidate);
							}
							requiredConstructor = candidate;
						}
						candidates.add(candidate);
					}
					else if (candidate.getParameterCount() == 0) {
						defaultConstructor = candidate;
					}
				}
				if (!candidates.isEmpty()) {
					// Add default constructor to list of optional constructors, as fallback.
					if (requiredConstructor == null) {
						if (defaultConstructor != null) {
							candidates.add(defaultConstructor);
						}
						else if (candidates.size() == 1 && logger.isWarnEnabled()) {
							logger.warn("Inconsistent constructor declaration on bean with name '" + beanName +
									"': single autowire-marked constructor flagged as optional - " +
									"this constructor is effectively required since there is no " +
									"default constructor to fall back to: " + candidates.get(0));
						}
					}
					candidateConstructors = candidates.toArray(new Constructor<?>[0]);
				}
				else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
					candidateConstructors = new Constructor<?>[] {rawCandidates[0]};
				}
				else if (nonSyntheticConstructors == 2 && primaryConstructor != null
						&& defaultConstructor != null && !primaryConstructor.equals(defaultConstructor)) {
					candidateConstructors = new Constructor<?>[] {primaryConstructor, defaultConstructor};
				}
				else if (nonSyntheticConstructors == 1 && primaryConstructor != null) {
					candidateConstructors = new Constructor<?>[] {primaryConstructor};
				}
				else {
					candidateConstructors = new Constructor<?>[0];
				}
				this.candidateConstructorsCache.put(beanClass, candidateConstructors);
			}
		}
	}
	return (candidateConstructors.length > 0 ? candidateConstructors : null);
}

     在前面的第5到第28行里,主要是看里面有没有Lookup的annotation。如果有这个的话,通过LookupOverride对象来设置对应的BeanDefinition。

    第31行的代码检查candidateConstructorsCache里是否有给定beanClass的constructor。如果没有,则先设置线程同步保证cache里的数据一致性,然后通过第38行的beanClass.getDeclaredConstructors来获取声明的构造函数。

     在得到所有的这些constructorCandidate之后,第50行遍历这个列表。遍历这个列表的目的主要是第57行的findAutowiredAnnotation方法。通过它来确认是否添加了Required属性。其中findAutowiredAnnotation方法根据给定的AccessibleObject来获取它被Autowired修饰后的元素。它的详细实现我们会在后面分析。

    接着的第58到第70行主要是处理当无法通过当前的class得到它的构造函数的话,尝试去获取它的父类的构造函数。

    第71行到89行用于判断它是否添加了required属性。针对各种错误情况进行处理。后面的第90行里的条件则是针对如果没有任何参数的话,就设定当前的这个函数作为默认的构造函数。

 

     我们接着看看findAutowiredAnnotation方法的详细实现:

 

private AnnotationAttributes findAutowiredAnnotation(AccessibleObject ao) {
	if (ao.getAnnotations().length > 0) {
		for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
			AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ao, type);
			if (attributes != null) {
				return attributes;
			}
		}
	}
	return null;
}

    在之前的方法里,我们是针对constructor进行分析。在java里,constructor, field等都是继承的AccessibleObject。表示它们都是可以被访问的对象。我们可以针对某些方面将他们一视同仁。它的流程相对比较简单点,主要是通过遍历现有的annotation,并和给定的constructor里的annotation进行merge处理,然后如果得到一个非空的属性则返回。

   前面这部分的代码是针对构造函数有Autowired annotation时是怎么处理的分析。它在整个bean框架中被调用的顺序如下图:

 

    从上图中可以看到,其实在前面构造bean对象的时候,这部分的方法会被调用处理。所以这里相当于前面处理解析各种文件和构造bean对象过程中某一个处理的点。接着的这部分代码是对方法和属性的依赖注入:

 

public PropertyValues postProcessPropertyValues(
		PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {

	InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
	try {
		metadata.inject(bean, beanName, pvs);
	}
	catch (BeanCreationException ex) {
		throw ex;
	}
	catch (Throwable ex) {
		throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
	}
	return pvs;
}

public void processInjection(Object bean) throws BeanCreationException {
	Class<?> clazz = bean.getClass();
	InjectionMetadata metadata = findAutowiringMetadata(clazz.getName(), clazz, null);
	try {
		metadata.inject(bean, null, null);
	}
	catch (BeanCreationException ex) {
		throw ex;
	}
	catch (Throwable ex) {
		throw new BeanCreationException(
				"Injection of autowired dependencies failed for class [" + clazz + "]", ex);
	}
}

    这两个方法是被调用的比较多的。他们主要的流程都是通过findAutowiringMetadata来获取到注入的元数据信息。然后再通过metadata的inject方法来注入指定的bean对象、类和相关的属性。所以关键点在于这两个方法。我们先来看findAutowiringMetadata方法:

 

private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
	// Fall back to class name as cache key, for backwards compatibility with custom callers.
	String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
	// Quick check on the concurrent map first, with minimal locking.
	InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
	if (InjectionMetadata.needsRefresh(metadata, clazz)) {
		synchronized (this.injectionMetadataCache) {
			metadata = this.injectionMetadataCache.get(cacheKey);
			if (InjectionMetadata.needsRefresh(metadata, clazz)) {
				if (metadata != null) {
					metadata.clear(pvs);
				}
				metadata = buildAutowiringMetadata(clazz);
				this.injectionMetadataCache.put(cacheKey, metadata);
			}
		}
	}
	return metadata;
}

     这个方法里前面通过injectionMetadataCache来查找给定的beanName或className。如果没找到,则通过buildAutowiringMetadata方法来获取metadata。获取到之后再将这部分metadata放到前面的cache里。我们再看buildAutowiringMetadata方法:

 

private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
	LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<>();
	Class<?> targetClass = clazz;

	do {
		final LinkedList<InjectionMetadata.InjectedElement> currElements = new LinkedList<>();

		ReflectionUtils.doWithLocalFields(targetClass, field -> {
			AnnotationAttributes ann = findAutowiredAnnotation(field);
			if (ann != null) {
				if (Modifier.isStatic(field.getModifiers())) {
					if (logger.isWarnEnabled()) {
						logger.warn("Autowired annotation is not supported on static fields: " + field);
					}
					return;
				}
				boolean required = determineRequiredStatus(ann);
				currElements.add(new AutowiredFieldElement(field, required));
			}
		});

		ReflectionUtils.doWithLocalMethods(targetClass, method -> {
			Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
			if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
				return;
			}
			AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod);
			if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
				if (Modifier.isStatic(method.getModifiers())) {
					if (logger.isWarnEnabled()) {
						logger.warn("Autowired annotation is not supported on static methods: " + method);
					}
					return;
				}
				if (method.getParameterCount() == 0) {
					if (logger.isWarnEnabled()) {
						logger.warn("Autowired annotation should only be used on methods with parameters: " +
								method);
					}
				}
				boolean required = determineRequiredStatus(ann);
				PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
				currElements.add(new AutowiredMethodElement(method, required, pd));
			}
		});

		elements.addAll(0, currElements);
		targetClass = targetClass.getSuperclass();
	}
	while (targetClass != null && targetClass != Object.class);

	return new InjectionMetadata(clazz, elements);
}

    这个方法看起来比较复杂,不过仔细整理下来,也并不是想象的那么困难。首先是在第2行里建立一个包含所有annotation元素的集合elements。在第5行开始的循环里,第8行到第20行是用来处理本地的成员变量。通过前面讨论的findAutowiredAnnotation方法找到被autowired annotation修饰的字段。然后判断它是否为static以及required的属性是否设置了。然后将找到的字段加入到当前的列表中。

    从第22行到第45行的代码里,则是针对本地方法的。它找到原来的方法之后,然后针对包含有Autowired annotation修饰的属性的方法做进一步的处理。然后判断required属性看是否为必须的。对于必须的部分再通过findPropertyForMethod来找到对应的属性描述部分。最后再构建一个对应的元素。经过这样的一通查找后,将所有合格的结果加入到返回的列表中。

    当然,在这个方法中,它会不断的从当前类到当前类的父类去重复上述的过程。第48行就是来改变当前类的。

    前面方法里还有一个依赖的实现方法findAutowiredAnnotation:

private AnnotationAttributes findAutowiredAnnotation(AccessibleObject ao) {
	if (ao.getAnnotations().length > 0) {
		for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
			AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ao, type);
			if (attributes != null) {
				return attributes;
			}
		}
	}
	return null;
}

     如果留意到前面构造函数里对autowiredAnnotationTypes进行初始化的部分,我们就会发现。前面就是对这个列表添加了Autowired.class, Value.class, Inject.class这三种类型的annotation。然后在这个循环里来尝试提取这些annotation属性。如果有的话,则将它们返回回来。

     在这里,针对字段的注入处理有专门的一个类AutowiredFieldElement,它继承了InjectionMetadata.InjectedElement。它对具体字段的注入实现在inject方法里:

 

protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
	Field field = (Field) this.member;
	Object value;
	if (this.cached) {
		value = resolvedCachedArgument(beanName, this.cachedFieldValue);
	}
	else {
		DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
		desc.setContainingClass(bean.getClass());
		Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
		Assert.state(beanFactory != null, "No BeanFactory available");
		TypeConverter typeConverter = beanFactory.getTypeConverter();
		try {
			value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
		}
		catch (BeansException ex) {
			throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
		}
		synchronized (this) {
			if (!this.cached) {
				if (value != null || this.required) {
					this.cachedFieldValue = desc;
					registerDependentBeans(beanName, autowiredBeanNames);
					if (autowiredBeanNames.size() == 1) {
						String autowiredBeanName = autowiredBeanNames.iterator().next();
						if (beanFactory.containsBean(autowiredBeanName) &&
								beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
							this.cachedFieldValue = new ShortcutDependencyDescriptor(
									desc, autowiredBeanName, field.getType());
						}
					}
				}
				else {
					this.cachedFieldValue = null;
				}
				this.cached = true;
			}
		}
	}
	if (value != null) {
		ReflectionUtils.makeAccessible(field);
		field.set(bean, value);
	}
}

     上述代码的实现过程如下。首先第4行的代码判断给定的bean是否已经被缓存了,如果是的,则通过resolvedCacheArgument方法来直接取得这个cached的值。否则从第8行起,构造一个DependencyDescriptor对象,然后通过beanFactory和构造的typeConverter来解析出来这个值。这部分的实现逻辑在第14行。第19行开始的部分同步来处理autowiredBeanNames。如果有,则默认按照类型注入。如果没有获取到的值为空或者本身这个值不是必须的,则设置这个cachedFieldValue为空。

    最后第40行的部分,如果依赖的值不为空,则将对应的bean设置为获取到的这个value值。    

 

    因为Autowired应用的范围比较广,这里针对方法里面的字段注入主要放在类AutowiredMethodElement里。它也是继承实现的InjectionMetadata.InjectedElement。这个方法的实现也叫inject:

 

 

//对方法进行注入
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
	//如果属性被显式设置为skip,则不进行注入
	if (checkPropertySkipping(pvs)) {
		return;
	}
	//获取注入元素对象
	Method method = (Method) this.member;
	try {
		Object[] arguments;
		//如果容器对当前方法缓存
		if (this.cached) {
			//获取缓存中指定Bean名称的方法参数
			arguments = resolveCachedArguments(beanName);
		}
		//如果没有缓存
		else {
			//获取方法的参数列表
			Class[] paramTypes = method.getParameterTypes();
			//创建一个存放方法参数的数组
			arguments = new Object[paramTypes.length];
			DependencyDescriptor[] descriptors = new DependencyDescriptor[paramTypes.length];
			Set<String> autowiredBeanNames = new LinkedHashSet<String>(paramTypes.length);
			//获取容器的类型转换器
			TypeConverter typeConverter = beanFactory.getTypeConverter();
			for (int i = 0; i < arguments.length; i++) {
				//创建方法参数对象
				MethodParameter methodParam = new MethodParameter(method, i);
		        //解析方法的输入参数和返回值类型	
                GenericTypeResolver.resolveParameterType(methodParam, bean.getClass());
				//为方法参数创建依赖描述符
				descriptors[i] = new DependencyDescriptor(methodParam, this.required);
				//根据容器中Bean定义解析依赖关系,获取方法参数依赖对象
				arguments[i] = beanFactory.resolveDependency(
						descriptors[i], beanName, autowiredBeanNames, typeConverter);
		        //如果容器解析的方法参数为null,且方法required属性为false
				if (arguments[i] == null && !this.required) {
					//设置方法的参数列表为null
					arguments = null;
					break;
				}
			}
			//线程同步,以确保容器中数据一致性
			synchronized (this) {
				//如果当前方法没有被容器缓存
				if (!this.cached) {
					//如果方法的参数列表不为空
					if (arguments != null) {
						//为容器中缓存方法参数的对象赋值
						this.cachedMethodArguments = new Object[arguments.length];
						for (int i = 0; i < arguments.length; i++) {
							this.cachedMethodArguments[i] = descriptors[i];
						}
						//为指定Bean注册依赖Bean
						registerDependentBeans(beanName, autowiredBeanNames);
						//如果依赖对象集合大小等于方法参数个数
						if (autowiredBeanNames.size() == paramTypes.length) {
							Iterator<String> it = autowiredBeanNames.iterator();
							//为方法参数设置依赖对象
							for (int i = 0; i < paramTypes.length; i++) {
								String autowiredBeanName = it.next();
								//如果容器中存在指定名称的Bean对象
								if (beanFactory.containsBean(autowiredBeanName)) {
									//如果参数类型和依赖对象类型匹配
									if (beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
                                        //创建一个依赖对象的引用,复制给方法相应的参数								
                                        this.cachedMethodArguments[i] = new RuntimeBeanReference(autowiredBeanName);
									}
								}
							}
						}
					}
					//如果方法参数列表为null,则设置容器对该方法参数的缓存为null
					else {
						this.cachedMethodArguments = null;
					}
					//设置容器已经对该方法缓存
					this.cached = true;
				}
			}
		}
		//如果方法参数依赖对象不为null
		if (arguments != null) {
			//使用JDK的反射机制,显式设置方法的访问控制权限为允许访问
			ReflectionUtils.makeAccessible(method);
			//调用Bean的指定方法
			method.invoke(bean, arguments);
		}
	}
	catch (InvocationTargetException ex) {
		throw ex.getTargetException();
	}
	catch (Throwable ex) {
		throw new BeanCreationException("Could not autowire method: " + method, ex);
	}
}

 

 

ConfigurationClassPostProcessor 

     还有一个比较重要而且常用的annotation就是Configuration了。在基于annotation开发的方法里,如果我们有必要自定义一些bean以及对应的配置信息,我们通常会使用到@Configuration来修饰这个定义bean相关信息的类。它相当于取代了对应的xml文件。那么,它的处理流程又是怎么样的呢?

    下图是对这个annotation处理的类结构。

 

   相应的,在ConfigurationClassPostProcessor里有具体的实现。它里面有两个方法牵涉到对应的解析处理工作。一个是postProcessBeanDefinitionRegistry, 一个是postProcessBeanFactory。这两个方法有一个共同依赖的方法processConfigBeanDefinitions。所有的代码如下,我们详细的分析一下: 

 

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
	int registryId = System.identityHashCode(registry);
	if (this.registriesPostProcessed.contains(registryId)) {
		throw new IllegalStateException(
				"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
	}
	if (this.factoriesPostProcessed.contains(registryId)) {
		throw new IllegalStateException(
				"postProcessBeanFactory already called on this post-processor against " + registry);
	}
	this.registriesPostProcessed.add(registryId);
	processConfigBeanDefinitions(registry);
}


public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
	List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
	String[] candidateNames = registry.getBeanDefinitionNames();

	for (String beanName : candidateNames) {
		BeanDefinition beanDef = registry.getBeanDefinition(beanName);
		if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
				ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
			if (logger.isDebugEnabled()) {
				logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
			}
		}
		else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
			configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
		}
	}

	// Return immediately if no @Configuration classes were found
	if (configCandidates.isEmpty()) {
		return;
	}

	// Sort by previously determined @Order value, if applicable
	configCandidates.sort((bd1, bd2) -> {
		int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
		int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
		return Integer.compare(i1, i2);
	});

	// Detect any custom bean name generation strategy supplied through the enclosing application context
	SingletonBeanRegistry sbr = null;
	if (registry instanceof SingletonBeanRegistry) {
		sbr = (SingletonBeanRegistry) registry;
		if (!this.localBeanNameGeneratorSet) {
			BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
			if (generator != null) {
				this.componentScanBeanNameGenerator = generator;
				this.importBeanNameGenerator = generator;
			}
		}
	}

	if (this.environment == null) {
		this.environment = new StandardEnvironment();
	}

	// Parse each @Configuration class
	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 {
		parser.parse(candidates);
		parser.validate();

		Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
		configClasses.removeAll(alreadyParsed);

		// Read the model and create bean definitions based on its content
		if (this.reader == null) {
			this.reader = new ConfigurationClassBeanDefinitionReader(
					registry, this.sourceExtractor, this.resourceLoader, this.environment,
					this.importBeanNameGenerator, parser.getImportRegistry());
		}
		this.reader.loadBeanDefinitions(configClasses);
		alreadyParsed.addAll(configClasses);

		candidates.clear();
		if (registry.getBeanDefinitionCount() > candidateNames.length) {
			String[] newCandidateNames = registry.getBeanDefinitionNames();
			Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
			Set<String> alreadyParsedClasses = new HashSet<>();
			for (ConfigurationClass configurationClass : alreadyParsed) {
				alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
			}
			for (String candidateName : newCandidateNames) {
				if (!oldCandidateNames.contains(candidateName)) {
					BeanDefinition bd = registry.getBeanDefinition(candidateName);
					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
							!alreadyParsedClasses.contains(bd.getBeanClassName())) {
						candidates.add(new BeanDefinitionHolder(bd, candidateName));
					}
				}
			}
			candidateNames = newCandidateNames;
		}
	}
	while (!candidates.isEmpty());

	// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
	if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
		sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
	}

	if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
		// Clear cache in externally provided MetadataReaderFactory; this is a no-op
		// for a shared cache since it'll be cleared by the ApplicationContext.
		((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
	}
}

public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
	Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
	for (String beanName : beanFactory.getBeanDefinitionNames()) {
		BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
		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.isWarnEnabled() && beanFactory.containsSingleton(beanName)) {
				logger.warn("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'.");
			}
			configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
		}
	}
	if (configBeanDefs.isEmpty()) {
		// nothing to enhance -> return immediately
		return;
	}

	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) {
				Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
				if (configClass != enhancedClass) {
					if (logger.isDebugEnabled()) {
						logger.debug(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);
		}
	}
}

     我们先来重点的看一下processConfigBeanDefinitions的实现。首先会通过对应的BeanDefinitionRegistry来取得对应的beanDefinitionNames列表。然后再遍历这个列表来获取对应的beanDefinition。如果它们已经是fullConfigurationClass,表示它们已经被处理过了,则直接返回。在这个循环里同时也检查当前的这个beanDefinition是否为ConfigureClass的候选。如果是,则加入到configCandiates列表里。

    在后面的步骤里会把这个configCandidates列表按照它里面定义的order进行排序。接着会判断当前的registry是否为SingletonBeanRegistry。如果是的,则通过它来获取对应的beanNameGenerator。后面会接着定义一个ConfigurationClassParser对象。在接着的这个大while循环里,每次它会对当前的candidates调用parse和validate方法。在处理完之后会将当前处理完的ConfigurationClass放到一个集合里,以后每次将当前处理过的加入到alreadyParsed里面来。在这个循环里,registry每次还会获取新的beanDefinitionNames,然后将新获得还没被处理的beanDefinition加到当前的candidates里来。一直重复上述的过程直到candidates列表为空。

 

 

总结

    对annotation的支持主要包含有对常用的一些annotation的解析和处理。它们大部分是通过 componentScan来扫描加载指定目录范围下的类层次,将对应的类族加载进来。然后对于常用的annotation像@Required, @Configuration, @Resource, @PostConstruct, @PreDestroy等等的处理都是通过BeanPostProcessor来处理。这样,对于新的实现的支持,也可以通过实现对应的接口加入注册到BeanPostProcessor列表里面来。在ApplicationContext的refresh方法过程里有专门遍历调用这些postProcessor的过程。

 

 

参考材料

https://blog.csdn.net/xieyuooo/article/details/9089441

https://blog.csdn.net/qq_27529917/article/details/78454929

https://blog.csdn.net/qq_27529917/article/details/78454912

https://muyinchen.github.io/2017/08/23/Spring5%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90-@Autowired/

https://www.mkyong.com/spring/spring-auto-scanning-components/

https://blog.csdn.net/xieyuooo/article/details/8002321

https://stackoverflow.com/questions/6827752/whats-the-difference-between-component-repository-service-annotations-in

https://blog.csdn.net/chjttony/article/details/6301523

https://blog.csdn.net/chjttony/article/details/6301591

  • 大小: 55.9 KB
  • 大小: 29.7 KB
  • 大小: 46.8 KB
  • 大小: 55.6 KB
  • 大小: 55.9 KB
  • 大小: 37.7 KB
  • 大小: 22.5 KB
分享到:
评论

相关推荐

    拦截器与冲突解决

    最后,对于提供的`interceptortest - 副本`文件,这可能是某个测试案例或示例代码,但具体的内容并未提供,因此无法给出具体的代码分析和解决方案。如果能提供这部分代码,我们将能够更具体地讨论冲突的解决方法。在...

    SpringMVC源码总结(二)mvc:mvc:annotation-driven背后的那些事

    在Spring MVC框架中,`mvc:annotation-driven`是Spring MVC配置中的一个重要元素,它使得我们的应用能够支持基于注解的控制器、数据绑定、格式化转换器和服务端验证等功能。这篇博客将深入探讨`mvc:annotation-...

    SpringMVC源码总结(三)mvc:annotation-driven和mvc:message-converters简单介绍

    `mvc:annotation-driven`是一个Spring MVC的XML配置元素,它简化了对注解驱动的控制器的支持。通过使用这个元素,我们可以启用Spring MVC自动扫描并处理带有`@Controller`注解的类,以及类中的`@RequestMapping`、`@...

    spring的annotation-driven配置事务管理器详解 (多数据源配置

    Spring 的 Annotation-Driven 配置事务管理器详解(多数据源配置) Spring 框架提供了强大的事务管理机制,通过使用 Annotation-Driven 配置,可以方便地管理事务。在多数据源配置中,spring 的 Annotation-Driven...

    Spring对注解(Annotation)处理源码分析

    Spring对注解(Annotation)处理源码分析 解析和注入注解配置的资源 源码级别的分析

    spring aop实例annotation方法实现

    本实例将详细探讨如何通过注解(Annotation)来实现Spring AOP的方法拦截。 一、Spring AOP基础 Spring AOP是Spring框架的一部分,它提供了一种在运行时织入横切关注点(如日志、事务管理等)到目标对象的能力。AOP...

    Spring源码学习十二:@Transactional是如何工作的1

    Spring 框架中 @Transactional 注解的工作原理分析 在 Spring 框架中,@Transactional 注解是一个非常重要的概念,经常用于数据库操作。那么,@Transactional 注解是如何工作的呢?让我们深入源码分析。 首先,从 ...

    Spring Annotation简介一

    【Spring Annotation简介一】 ...在实际项目中,结合源码分析,可以更深入地理解Spring框架的工作原理,提升自己的技能水平。通过工具,如IDEA的Spring插件,可以方便地查看和管理注解,进一步优化开发流程。

    spring源码解析:元注解功能的实现.doc

    在Spring框架中,元注解(Meta-Annotation)是一种用于注解其他注解的特殊注解,它使得Spring能够提供更灵活...通过深入理解Spring源码中的元注解实现,开发者可以更好地利用Spring框架,定制适合自己项目的注解体系。

    Spring注释 注入方式源码示例,Annotation

    花了些时间做了一个实验,彻底弄懂了spring Annotation注入的方式。凡带有@Component,@Controller,@Service,@Repository 标志的等于告诉Spring这类将自动产生对象,而@Resource则等于XML配置中的ref,告诉spring此处...

    4Spring自动装配——annotation resource方式

    本文将深入探讨如何通过注解(Annotation)和`@Resource`来实现自动装配,以及其背后的源码实现。 ### 一、注解驱动的自动装配 在Spring 2.5引入了注解支持后,开发者可以使用注解来声明Bean的属性、方法或构造...

    Spring annotation

    - `@RunWith(SpringRunner.class)`: 使用Spring JUnit支持运行测试类。 - `@SpringBootTest`: 创建一个Spring Boot应用上下文,可用于测试整个应用。 - `@WebMvcTest`: 专注于Spring MVC层的测试,只启动Web相关...

    Spring 常用 Transaction Annotation

    在Spring框架中,事务管理是实现业务逻辑的重要组成部分,它确保了数据的一致性和完整性。Spring提供了多种方式来处理事务,其中包括编程式事务管理和声明式事务管理。本篇主要聚焦于"Spring 常用 Transaction ...

    spring-framework-2.0 Java源代码,spring2源代码

    Spring 框架是Java开发领域中的一个核心框架,它为构建高质量的、松耦合的应用程序提供了...对于想要深入理解Spring框架的开发者来说,研究其源代码是极有价值的,能够帮助他们更好地运用和定制Spring,提升开发技能。

    mybatis学习总结:annotation示例改进

    在实际项目中,我们不仅要理解这些基本用法,还要学会根据具体需求进行调整和优化,以实现最佳的代码结构和性能。对于初学者来说,参考提供的博客链接(https://shmilyaw-hotmail-com.iteye.com/blog/2354678)会是...

    学习Spring笔记_AOP_Annotation实现和XML实现

    这篇“学习Spring笔记_AOP_Annotation实现和XML实现”主要探讨了如何在Spring中利用注解和XML配置来实现AOP的概念。 AOP,全称Aspect-Oriented Programming,是一种编程范式,旨在将关注点分离,让开发者可以更专注...

    探索Java注解的神秘世界:Annotation全解析

    3. **代码生成**:利用注解处理器在编译时自动生成代码,比如使用 Google 的 AutoValue 库来自动生成不可变对象的源代码。 4. **性能优化**:如使用 `@Cacheable` 来缓存方法的结果以提高性能。 5. **安全认证**:...

    hibernate和spring源代码

    【hibernate和spring源代码】的分析与详解 Hibernate是一个强大的对象关系映射(ORM)框架,它在Java开发中被广泛使用,为开发者提供了便捷的数据持久化服务。3.3.2.GA版本是Hibernate的一个稳定版本,它包含了对...

Global site tag (gtag.js) - Google Analytics