zoukankan      html  css  js  c++  java
  • @autowire、@resource原理

    @autowire、@resource、@value是我们项目开发中最常用的注解。

    对于初学者来说

    @value注入配置属性

    @autowire根据类型注入

    @resource根据名字注入

    其实这种理解不是很透彻

    今天我们来探索下@autowire的原理。

    一、准备测试代码

    一个接口类有多个实现类

    public interface UserService {
    
    }
    

    --

    @Service("userService1")
    public class UserService1Impl implements UserService {
    
    }
    

    --
    @Service("userService2")
    public class UserService2Impl implements UserService {

    }
    

    需要注入的类

    public interface UniqueService {
    
        void a();
    
    }
    

    --
    @Service
    public class UniqueServiceImpl implements UniqueService {

        @Autowired
        private UserService userService1;
    
        @Value("${test.a}")
        private String a;
    
        @Override
        public void a() {
            System.out.println(a);
        }
    }
    

    xml配置

    <context:property-placeholder location="classpath:application.properties"/>
    <context:component-scan base-package="com.csy.discuss.core.autowire"/>
    

    二、源码分析

    1.AutowiredAnnotationBeanPostProcessor初始化

    注:这一点其实大部分知识点都与Spring容器的初始化和Spring命名空间有关。

    当spring解析<context:component-scan>标签的时候找到对应的ComponentScanBeanDefinitionParser命名空间解析器

    //ComponentScanBeanDefinitionParser#registerComponents

    protected void registerComponents(
    			XmlReaderContext readerContext, Set<BeanDefinitionHolder> beanDefinitions, Element element) {
    
    	...
    
    	// Register annotation config processors, if necessary.
    	boolean annotationConfig = true;
    	if (element.hasAttribute(ANNOTATION_CONFIG_ATTRIBUTE)) {
    		annotationConfig = Boolean.valueOf(element.getAttribute(ANNOTATION_CONFIG_ATTRIBUTE));
    	}
    	if (annotationConfig) {
    		Set<BeanDefinitionHolder> processorDefinitions =
    				AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source);
    		for (BeanDefinitionHolder processorDefinition : processorDefinitions) {
    			compositeDef.addNestedComponent(new BeanComponentDefinition(processorDefinition));
    		}
    	}
    
    	readerContext.fireComponentRegistered(compositeDef);
    }
    

    因为<context:component-scan>标签annotation-config属性默认为true。所以
    调用AnnotationConfigUtils.registerAnnotationConfigProcessors。
    里面手动注册了AutowiredAnnotationBeanPostProcessor这个bean。

    Spring创建AutowiredAnnotationBeanPostProcessor这个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.
    	}
    }
    

    我们可以看到。它初始化了Autowired、Value、Inject三个注解。也就是说这三个注解都是由AutowiredAnnotationBeanPostProcessor来实现的。

    2.组装InjectionMetadata

    private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
    	LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>();
    	Class<?> targetClass = clazz;
    
    	do {
    		final LinkedList<InjectionMetadata.InjectedElement> currElements =
    				new LinkedList<InjectionMetadata.InjectedElement>();
    
    		ReflectionUtils.doWithLocalFields(targetClass, new ReflectionUtils.FieldCallback() {
    			@Override
    			public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
    				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, new ReflectionUtils.MethodCallback() {
    			@Override
    			public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
    				...
    			}
    		});
    
    		elements.addAll(0, currElements);
    		targetClass = targetClass.getSuperclass();
    	}
    	while (targetClass != null && targetClass != Object.class);
    
    	return new InjectionMetadata(clazz, elements);
    }
    

    我们可以看两个主方法:doWithLocalFields和doWithLocalMethods。顾名思义,处理属性和方法上的@autowire类注解。也就是说@autowire不仅可以打在类的属性上,还能打在类的方法上。打在方法上我们不做分析,因为基本不用。
    然后遍历这个类上所有的属性。筛选出带有@Autowire或@Value或@Inject的属性。最终组装成InjectionMetadata。

    3.注入

    doCreateBean -> populateBean -> InstantiationAwareBeanPostProcessor#postProcessPropertyValues

    AutowiredAnnotationBeanPostProcessor就是继承InstantiationAwareBeanPostProcessor。

    public PropertyValues postProcessPropertyValues(
    			PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
    
    	InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
    	try {
    	   // AutowiredFieldElement.inject
    		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;
    }
    

    首先,就是拿到我们第二步组装好的InjectionMetadata,然后遍历里面的InjectedElement。即遍历这个bean所有带有@Autowire或@Value或@Inject的属性。

    AutowiredAnnotationBeanPostProcessor有两个私有内部类AutowiredFieldElement和AutowiredMethodElement,都继承InjectionMetadata的内部类InjectedElement。显而易见,我们要跟踪的是AutowiredFieldElement。

    //DefaultListableBeanFactory

    public Object doResolveDependency(DependencyDescriptor descriptor, String beanName,
    			Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {
    
    	InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
    	try {
    		Object shortcut = descriptor.resolveShortcut(this);
    		if (shortcut != null) {
    			return shortcut;
    		}
    
    		Class<?> type = descriptor.getDependencyType();
    		Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
    		
    		//@Value注解走这里
    		if (value != null) {
    			if (value instanceof String) {
    				String strVal = resolveEmbeddedValue((String) value);
    				BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);
    				value = evaluateBeanDefinitionString(strVal, bd);
    			}
    			TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
    			return (descriptor.getField() != null ?
    					converter.convertIfNecessary(value, type, descriptor.getField()) :
    					converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
    		}
          
            //@Autowire注解走这里
    		Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
    		if (multipleBeans != null) {
    			return multipleBeans;
    		}
    
    		Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
    		if (matchingBeans.isEmpty()) {
    			if (isRequired(descriptor)) {
    				raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
    			}
    			return null;
    		}
    
    		String autowiredBeanName;
    		Object instanceCandidate;
    
    		if (matchingBeans.size() > 1) {
    			autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
    			if (autowiredBeanName == null) {
    				if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
    					return descriptor.resolveNotUnique(type, matchingBeans);
    				}
    				else {
    					// In case of an optional Collection/Map, silently ignore a non-unique case:
    					// possibly it was meant to be an empty collection of multiple regular beans
    					// (before 4.3 in particular when we didn't even look for collection beans).
    					return null;
    				}
    			}
    			instanceCandidate = matchingBeans.get(autowiredBeanName);
    		}
    		else {
    			// We have exactly one match.
    			Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
    			autowiredBeanName = entry.getKey();
    			instanceCandidate = entry.getValue();
    		}
    
    		if (autowiredBeanNames != null) {
    			autowiredBeanNames.add(autowiredBeanName);
    		}
    		return (instanceCandidate instanceof Class ?
    				descriptor.resolveCandidate(autowiredBeanName, type, this) : instanceCandidate);
    	}
    	finally {
    		ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
    	}
    }
    

    3.1@Value注解链路

    这个不多分析了。主要通过PropertySourcesPlaceholderConfigurer去解析

    3.2@Autowire注解链路

    以测试代码注入的UserService userService1为例。

    Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
    

    candidates老朋友了,候选者的意思。

    从bean工厂中捞出UserService类型的bean。以这个bean的名字为key。若bean已经创建完成,那么以这个bean的实例为value。否则以这个bean的类型为value;

    对于测试代码的例子来说。有两个候选者。分别是userService1和userService2

    如果matchingBeans有多个,那就根据对应属性的名字进行匹配。

    return (instanceCandidate instanceof Class ?
    					descriptor.resolveCandidate(autowiredBeanName, type, this) : instanceCandidate);
    

    如果是class类型那么调用beanFactory.getBean进行bean的创建,拿到这个bean的实例。

    AutowiredFieldElement#inject的最后几句代码

    if (value != null) {
    	ReflectionUtils.makeAccessible(field);
    	field.set(bean, value);
    }
    

    通过反射将属性设置进去。

    四、顺便提一下@Resource注解

    由CommonAnnotationBeanPostProcessor实现

    看beanDefinitionMap里是否有这个属性名称的bean。没有的话根据类型走和@autowire一样的doResolveDependency方法。有这个属性名称的bean,直接创建这个bean。

    总结

    1.@autowire、@resource、@value是通过调用AutowiredAnnotationBeanPostProcessor这个BeanPostProsess的postProcessPropertyValues方法进行注入的

    2.@Autowire不仅可以作用在bean的属性上,还能作用在bean的方法上。

    3.@Autowire通过属性的类型进行注入。若这个类型有多种(一个接口类有多个实现类),降级为根据名字来注入

    4.@Resource通过属性的名字去容器里找bean的定义。有的话直接创建bean进行注入。没有的话降级为根据类型进行注入

  • 相关阅读:
    安装VS2003出现“FrontPage 2000 WEB 扩展客户端”安装失败时
    字符编码:ASCII,Unicode和UTF8
    AWK学习笔记
    static关键字用法总结
    拷贝构造函数,浅拷贝与深拷贝
    安装IIS步骤图解
    配置SQL Server 2005 Express的身份验证方式,以及如何启用sa登录名
    ASP.NET的学习
    C# 中的委托和事件(转)
    OSI七层模型
  • 原文地址:https://www.cnblogs.com/chenshengyue/p/11453953.html
Copyright © 2011-2022 走看看