zoukankan      html  css  js  c++  java
  • @Autowired注解源码解析

    我们先来写一个简单的demo方便debug调试。

    public class QualifierDemo {
    
        public static void main(String[] args) {
            AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext();
            applicationContext.register(QualifierDemo.class);
            applicationContext.refresh();
    
            applicationContext.close();
        }
    
        @Autowired
        private User user;
    
    
        @Bean
        public User user(){
            return createUser("user1");
        }
    
        private static User createUser(String name){
            User user=new User();
            user.setName(name);
            return user;
        }
    }
    

    首先我们来关注这个方法AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition,这个类实现了BeanPostProcessor的子接口,所以bean在实例化的时候会执行到这个方法。

        @Override
    	public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
    	    //获取加了@Autowired的元信息数据
    		InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
    		//将beanDefinition里Autowired相关信息添加到checkedElements里面,后面会用到。
    		metadata.checkConfigMembers(beanDefinition);
    	}
    

    我们可以看到上面这个方法到入参里有个beanDefinition,这个beanDefinition正是QualifierDemo的实例,然后通过findAutowiringMetadata方法会去找关于Autowired的元信息。
    这个方法执行完后,会执行AutowiredAnnotationBeanPostProcessor#postProcessProperties方法。

    @Override
    	public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
    	    //获取一些元信息
    		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;
    	}
    

    这里面关键的方法就是inject方法,他的代码如下:

    public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
            //取之前存入的checkedElements
    		Collection<InjectedElement> checkedElements = this.checkedElements;
    		//没有的话就取injectedElements,也是之前存入的
    		Collection<InjectedElement> elementsToIterate =
    				(checkedElements != null ? checkedElements : this.injectedElements);
    		if (!elementsToIterate.isEmpty()) {
    		    //遍历@Autowired注解标记了的元信息数据集合,我们的示例中只有一个@Autowired  User
    			for (InjectedElement element : elementsToIterate) {
    				if (logger.isTraceEnabled()) {
    					logger.trace("Processing injected element of bean '" + beanName + "': " + element);
    				}
    				//element正是我们示例代码里的User的一些描述
    				element.inject(target, beanName, pvs);
    			}
    		}
    	}
    

    element的结构图如下:

    可以看出,这个类型就是我们的User。接着往下看element#inject方法。

            @Override
    		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 {
    				    //根据元信息描述去进行bean查找
    					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;
    					}
    				}
    			}
    			//将查找到的bean通过反射set到对象中及示例中的 @Autowired private User user;
    			if (value != null) {
    			    //反射操作给private属性需要的操作。
    				ReflectionUtils.makeAccessible(field);
    				field.set(bean, value);
    			}
    		}
    	}
    

    通过反射将查找到到bean注入到@Autowired注解到变量上。

    另外,源码中分析要经过的两个方法postProcessMergedBeanDefinition和postProcessProperties,他们是因为实现了spring的接口,所以会被调用到。下面我们写个例子证实它。

    @Configuration
    public class BeanPostConfig implements MergedBeanDefinitionPostProcessor, InstantiationAwareBeanPostProcessor {
        @Override
        public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
            System.out.println("postProcessMergedBeanDefinition:"+beanName);
        }
    
    
        @Override
        public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
            System.out.println("postProcessProperties:"+beanName);
            return pvs;
        }
    }
    

    打印结果如下:

    postProcessMergedBeanDefinition:qualifierDemo
    postProcessMergedBeanDefinition:user
    postProcessProperties:user
    postProcessProperties:qualifierDemo

    事实证明实现了接口后,两个方法都被执行了,并且会将postProcessMergedBeanDefinition方法执行完之后才开始调用postProcessProperties方法。

  • 相关阅读:
    推荐一波好的代码托管
    二十一、如何导入svg图片
    二十、滑动开关css
    十九、CSS如何引入字体
    十八、移动端rem布局
    十五、css3 Filter--滤镜
    十四、css动画基础知识
    十三、初始化标签默认样式
    十二、移动端头部声明
    十一、使用a标签打电话、发短信、发邮件
  • 原文地址:https://www.cnblogs.com/javammc/p/13636380.html
Copyright © 2011-2022 走看看