除了使用xml文件配置以外,spring还支持使用注解实现JavaBean的配置,其具体实现方式网上已经介绍的很详细,这里就不再赘述了。本文将主要通过源代码解析spring注解配置JavaBean的全过程。这里主要分析的是@component和@Autowired这两个注解。
首先要明确这样一个问题,注解配置和xml文件配置二者并“完全”不冲突。说不完全是因为如果使用@component修饰一个类,那么就无法通过xml为这个类设置某些参数,如property的值。但是通过xml文件配置的JavaBean则可以使用@Autowired完成属性的配置。这个问题说明了注解配置方法是xml文件配置方法的进化版,并且是依附于xml文件配置的。下面将主要介绍其实现原理。
使用注解配置方法的xml文件配置:
- <context:component-scan base-package="com.luanbin.annotation" />
根据上一篇博客的介绍,可以找到这个component-scan对应的解析类AnnotationConfigBeanDefinitionParser
该解析类的parse方法:
- public BeanDefinition parse(Element element, ParserContext parserContext) {
- Object source = parserContext.extractSource(element);
-
-
- Set processorDefinitions =
- AnnotationConfigUtils.registerAnnotationConfigProcessors(parserContext.getRegistry(), source);
-
-
- CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source);
- parserContext.pushContainingComponent(compDefinition);
-
-
- for (BeanDefinitionHolder processorDefinition : processorDefinitions) {
- parserContext.registerComponent(new BeanComponentDefinition(processorDefinition));
- }
-
-
- parserContext.popAndRegisterContainingComponent();
-
- return null;
- }
parse方法只完成了一项工作,扫描指定的package,同时将被@component修饰的类包装成beandefinition,需要尤其注意的事,因为注解相比于xml文件拥有的信息较少,因此该beandefinition除了实现类,即被@component修饰的类信息以外,不包含其他信息,如构造函数,各个property的属性等。JavaBean在AbstractAutowireCapableBeanFactory的doCreatBean函数中被实例化并且配置相关属性,其具体代码如下:
- protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
-
- BeanWrapper instanceWrapper = null;
- if (mbd.isSingleton()) {
- instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
- }
- if (instanceWrapper == null) {
- instanceWrapper = createBeanInstance(beanName, mbd, args);
- }
- final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
- Class beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
-
-
- synchronized (mbd.postProcessingLock) {
- if (!mbd.postProcessed) {
- applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
- mbd.postProcessed = true;
- }
- }
-
-
-
- boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
- isSingletonCurrentlyInCreation(beanName));
- if (earlySingletonExposure) {
- if (logger.isDebugEnabled()) {
- logger.debug("Eagerly caching bean '" + beanName +
- "' to allow for resolving potential circular references");
- }
- addSingletonFactory(beanName, new ObjectFactory() {
- public Object getObject() throws BeansException {
- return getEarlyBeanReference(beanName, mbd, bean);
- }
- });
- }
-
-
- Object exposedObject = bean;
- try {
- populateBean(beanName, mbd, instanceWrapper);
- if (exposedObject != null) {
- exposedObject = initializeBean(beanName, exposedObject, mbd);
- }
- }
- catch (Throwable ex) {
- if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
- throw (BeanCreationException) ex;
- }
- else {
- throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
- }
- }
-
- if (earlySingletonExposure) {
- Object earlySingletonReference = getSingleton(beanName, false);
- if (earlySingletonReference != null) {
- if (exposedObject == bean) {
- exposedObject = earlySingletonReference;
- }
- else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
- String[] dependentBeans = getDependentBeans(beanName);
- Set actualDependentBeans = new LinkedHashSet(dependentBeans.length);
- for (String dependentBean : dependentBeans) {
- if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
- actualDependentBeans.add(dependentBean);
- }
- }
- if (!actualDependentBeans.isEmpty()) {
- throw new BeanCurrentlyInCreationException(beanName,
- "Bean with name '" + beanName + "' has been injected into other beans [" +
- StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
- "] in its raw version as part of a circular reference, but has eventually been " +
- "wrapped. This means that said other beans do not use the final version of the " +
- "bean. This is often the result of over-eager type matching - consider using " +
- "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
- }
- }
- }
- }
-
-
- try {
- registerDisposableBeanIfNecessary(beanName, bean, mbd);
- }
- catch (BeanDefinitionValidationException ex) {
- throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
- }
-
- return exposedObject;
- }
其中createBeanInstance(beanName, mbd, args)的功能是根据beandefinition反射出来累的构造函数,并通过构造函数完成JavaBean的实例化,其具体代码如下:
- protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
-
- Class beanClass = resolveBeanClass(mbd, beanName);
-
- if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
- throw new BeanCreationException(mbd.getResourceDescription(), beanName,
- "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
- }
-
- if (mbd.getFactoryMethodName() != null) {
- return instantiateUsingFactoryMethod(beanName, mbd, args);
- }
-
-
- boolean resolved = false;
- boolean autowireNecessary = false;
- if (args == null) {
- synchronized (mbd.constructorArgumentLock) {
- if (mbd.resolvedConstructorOrFactoryMethod != null) {
- resolved = true;
- autowireNecessary = mbd.constructorArgumentsResolved;
- }
- }
- }
- if (resolved) {
- if (autowireNecessary) {
- return autowireConstructor(beanName, mbd, null, null);
- }
- else {
- return instantiateBean(beanName, mbd);
- }
- }
-
-
- Constructor[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
- if (ctors != null ||
- mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
- mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
- return autowireConstructor(beanName, mbd, ctors, args);
- }
-
-
- return instantiateBean(beanName, mbd);
- }
在完成JavaBean的实例化之后,spring通过BeanPostProcessor对该JavaBean进行处理。
- applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
其中AutowiredAnnotationBeanPostProcessor的主要工作就是判断JavaBean中是否有被@Autowired修饰的field和method,并将该信息包装成InjecMetadata保存在list中。其核心代码如下:
- private InjectionMetadata findAutowiringMetadata(Class> clazz) {
-
- InjectionMetadata metadata = this.injectionMetadataCache.get(clazz);
- if (metadata == null) {
- synchronized (this.injectionMetadataCache) {
- metadata = this.injectionMetadataCache.get(clazz);
- if (metadata == null) {
- metadata = buildAutowiringMetadata(clazz);
- this.injectionMetadataCache.put(clazz, metadata);
- }
- }
- }
- return metadata;
- }
和xml配置的JavaBean一样,spring通过populateBean方法完成JavaBean中被@Autowired所修饰的属性的注入。而注入的过程依旧是调用
BeanPostProcessor的相关方法。注入的方法如下:
- public PropertyValues postProcessPropertyValues(
- PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
-
- InjectionMetadata metadata = findAutowiringMetadata(bean.getClass());
- try {
- metadata.inject(bean, beanName, pvs);
- }
- catch (Throwable ex) {
- throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
- }
- return pvs;
- }
而metadata的注入过程实际上就是从beanfactory中获取JavaBean的实例并配置到目标bean上。可以看得出来,这种实例化方法存在递归过程。因此在实例化之前,spring会检测是否存在循环依赖,检测循环依赖的方法将在之后进行介绍。