欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-04-02 16:49:55
...

简介

    在之前的文章里,我们讨论了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关系图的过程。 那里讲到读取和解析文件的流程时,有这么一个顺序图:

 

spring源代码分析:annotation支持的实现
            
    
    博客分类: javaspring

    这里有一个很关键的类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的资源并加载进来。

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

spring源代码分析:annotation支持的实现
            
    
    博客分类: javaspring

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

spring源代码分析:annotation支持的实现
            
    
    博客分类: javaspring

    从最开始的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这些的支持实现都在这里。它相关的类结构图如下: 

spring源代码分析:annotation支持的实现
            
    
    博客分类: javaspring

    它的初始化和销毁对象的定义继承自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

 

spring源代码分析:annotation支持的实现
            
    
    博客分类: javaspring

 

 

 

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相关的类结构图如下:

spring源代码分析:annotation支持的实现
            
    
    博客分类: javaspring

    在这个图里可以看到,它实现了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框架中被调用的顺序如下图:

 

spring源代码分析:annotation支持的实现
            
    
    博客分类: javaspring

    从上图中可以看到,其实在前面构造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处理的类结构。

 

spring源代码分析:annotation支持的实现
            
    
    博客分类: javaspring

   相应的,在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://*.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

  • spring源代码分析:annotation支持的实现
            
    
    博客分类: javaspring
  • 大小: 55.9 KB
  • spring源代码分析:annotation支持的实现
            
    
    博客分类: javaspring
  • 大小: 29.7 KB
  • spring源代码分析:annotation支持的实现
            
    
    博客分类: javaspring
  • 大小: 46.8 KB
  • spring源代码分析:annotation支持的实现
            
    
    博客分类: javaspring
  • 大小: 55.6 KB
  • spring源代码分析:annotation支持的实现
            
    
    博客分类: javaspring
  • 大小: 55.9 KB
  • spring源代码分析:annotation支持的实现
            
    
    博客分类: javaspring
  • 大小: 37.7 KB
  • spring源代码分析:annotation支持的实现
            
    
    博客分类: javaspring
  • 大小: 22.5 KB