你有没有思考过Spring中的@Autowired注解?一般用于方便依赖注入,而隐藏在这个过程以后的机制究竟是怎样,将在本篇中进行讲述。
@Autowired是一个用来执行依赖注入的注解。每当一个Spring管理的bean发现有这个注解时候,它会直接注入相应的另外一个Spring管理的bean。java
该注解能够在不一样的层次上应用:git
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'testController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void org.krams.tutorial.controller.TestController.ix(com.mysite.controller.IndexController,com.mysite.nospring.data.Article); nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.mysite.nospring.data.Article] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {} 复制代码
对象注入须要遵循一些规则。一个bean能够按照下面的方式注入: github
在某些状况下,@Autowired应该经过@Qualifier注解协做注入。例以下面几个是相同类型的bean:spring
<bean name="comment1" class="com.waitingforcode.Comment"> <property name="text" value="Content of the 1st comment" /> </bean> <bean name="comment2" class="com.waitingforcode.Comment"> <property name="text" value="Content of the 2nd comment" /> </bean> 复制代码
上面这种状况,假如只是一个简单的@Autowired,Spring根本不知道你要注入哪一个bean。这就是为何咱们要使用@Qualifier(value =“beanName”)这个注解。在咱们的例子中,要从 com.waitingforcode.Comment这个类型的bean中区分comment1,comment2,咱们能够写下面的代码:bootstrap
@Qualifier(value="comment1") @Autowired private Comment firstComment; @Qualifier(value="comment2") @Autowired private Comment secondComment; 复制代码
正如前面部分所看到的,咱们知道了在Spring中实现@Autowired的不一样方法。在这一部分中,咱们将使用XML配置的方式激活@Autowired注解来自动注入。而后,咱们将编写一个简单的类并配置一些bean。最后,咱们将分别在另外两个类中使用它们:由@Controller注解的控件和不禁Spring所管理的类。(为何用XML配置来作例子,我以为这样更直观,其实XML和使用注解没多少区别,都是往容器里添加一些bean和组织下彼此之间的依赖而已,没必要要非要拘泥于一种形式,哪一种顺手用哪一种,不过Springboot自定义的这些仍是推荐使用注解了)markdown
咱们从启动注解的自动注入开始:app
<context:annotation-config />
复制代码
你必须将上面这个放在应用程序上下文配置中。它可使在遇到@Autowired注解时启用依赖注入。ide
如今,咱们来编写和配置咱们的bean:函数
// beans first public class Comment { private String content; public void setContent(String content) { this.content = content; } public String getContent() { return this.content; } } // sample controller @Controller public class TestController { @Qualifier(value="comment1") @Autowired private Comment firstComment; @Qualifier(value="comment2") @Autowired private Comment secondComment; @RequestMapping(value = "/test", method = RequestMethod.GET) public String test() { System.out.println("1st comment text: "+firstComment.getText()); System.out.println("2nd comment text: "+secondComment.getText()); return "test"; } } // no-Spring managed class public class TestNoSpring { @Autowired private Comment comment; public void testComment(String content) { if (comment == null) { System.out.println("Comment's instance wasn't autowired because this class is not Spring-managed bean"); } else { comment.setContent(content); System.out.println("Comment's content: "+comment.getContent()); } } } 复制代码
XML配置(在前面部分已经看到过):oop
<bean name="comment1" class="com.specimen.exchanger.Comment"> <property name="content" value="Content of the 1st comment" /> </bean> <bean name="comment2" class="com.specimen.exchanger.Comment"> <property name="content" value="Content of the 2nd comment" /> </bean> 复制代码
如今,咱们打开http://localhost:8080/test来运行TestController。如预期的那样,TestController的注解字段正确地自动注入,而TestNoSpring的注解字段并无注入进去:
1st comment text: Content of the 1st comment 2nd comment text: Content of the 2nd comment Comment's instance wasn't autowired because this class is not Spring-managed bean 复制代码
哪里不对 ?TestNoSpring类不禁Spring所管理。这就是为何Spring不能注入Comment实例的依赖。咱们将在下一部分中解释这个概念。
在讨论代码细节以前,咱们再来了解下基础知识。Spring管理可用于整个应用程序的Java对象bean。他们所在的Spring容器,被称为应用程序上下文。这意味着咱们不须要处理他们的生命周期(初始化,销毁)。该任务由此容器来完成。另外,该上下文具备入口点,在Web应用程序中,是dispatcher servlet。容器(也就是该上下文)会在它那里被启动而且全部的bean都会被注入。
说的再清楚点,请看<context:annotation-config />的定义:
<xsd:element name="annotation-config"> <xsd:annotation> <xsd:documentation><![CDATA[ Activates various annotations to be detected in bean classes: Spring's @Required and @Autowired, as well as JSR 250's @PostConstruct, @PreDestroy and @Resource (if available), JAX-WS's @WebServiceRef (if available), EJB 3's @EJB (if available), and JPA's @PersistenceContext and @PersistenceUnit (if available). Alternatively, you may choose to activate the individual BeanPostProcessors for those annotations. Note: This tag does not activate processing of Spring's @Transactional or EJB 3's @TransactionAttribute annotation. Consider the use of the <tx:annotation-driven> tag for that purpose. See javadoc for org.springframework.context.annotation.AnnotationConfigApplicationContext for information on code-based alternatives to bootstrapping annotation-driven support. ]]></xsd:documentation> </xsd:annotation> </xsd:element> 复制代码
能够看出 : 类内部的注解,如:@Autowired、@Value、@Required、@Resource以及EJB和WebSerivce相关的注解,是容器对Bean对象实例化和依赖注入时,经过容器中注册的Bean后置处理器处理这些注解的。
因此配置了上面这个配置(<context:component-scan>假若有配置这个,那么就能够省略<context:annotation-config />)后,将隐式地向Spring容器注册AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、RequiredAnnotationBeanPostProcessor、PersistenceAnnotationBeanPostProcessor以及这4个专门用于处理注解的Bean后置处理器。
当 Spring 容器启动时,AutowiredAnnotationBeanPostProcessor 将扫描 Spring 容器中全部 Bean,当发现 Bean 中拥有@Autowired 注解时就找到和其匹配(默认按类型匹配)的 Bean,并注入到对应的地方中去。 源码分析以下:
经过org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor能够实现依赖自动注入。经过这个类来处理@Autowired和@Value这俩Spring注解。它也能够管理JSR-303的@Inject注解(若是可用的话)。在AutowiredAnnotationBeanPostProcessor构造函数中定义要处理的注解:
public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware { ... /** * Create a new AutowiredAnnotationBeanPostProcessor * for Spring's standard {@link Autowired} annotation. * <p>Also supports JSR-330's {@link javax.inject.Inject} annotation, if available. */ @SuppressWarnings("unchecked") 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注解进行处理。
第一个,private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz)解析等待自动注入类的全部属性。它经过分析全部字段和方法并初始化org.springframework.beans.factory.annotation.InjectionMetadata类的实例来实现。
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 -> { //findAutowiredAnnotation(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); //返回一个InjectionMetadata初始化的对象实例 return new InjectionMetadata(clazz, elements); } ... /** * 'Native' processing method for direct calls with an arbitrary target instance, * resolving all of its fields and methods which are annotated with {@code @Autowired}. * @param bean the target instance to process * @throws BeanCreationException if autowiring failed */ 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); } } 复制代码
InjectionMetadata类包含要注入的元素的列表。注入是经过Java的API Reflection (Field set(Object obj, Object value) 或Method invoke(Object obj,Object ... args)方法完成的。此过程直接在AutowiredAnnotationBeanPostProcessor的方法中调用public void processInjection(Object bean) throws BeanCreationException。它将全部可注入的bean检索为InjectionMetadata实例,并调用它们的inject()方法。
public class InjectionMetadata { ... public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable { Collection<InjectedElement> checkedElements = this.checkedElements; Collection<InjectedElement> elementsToIterate = (checkedElements != null ? checkedElements : this.injectedElements); if (!elementsToIterate.isEmpty()) { boolean debug = logger.isDebugEnabled(); for (InjectedElement element : elementsToIterate) { if (debug) { logger.debug("Processing injected element of bean '" + beanName + "': " + element); } //看下面静态内部类的方法 element.inject(target, beanName, pvs); } } } ... public static abstract class InjectedElement { protected final Member member; protected final boolean isField; ... /** * Either this or {@link #getResourceToInject} needs to be overridden. */ protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs) throws Throwable { if (this.isField) { Field field = (Field) this.member; ReflectionUtils.makeAccessible(field); field.set(target, getResourceToInject(target, requestingBeanName)); } else { if (checkPropertySkipping(pvs)) { return; } try { //具体的注入看此处咯 Method method = (Method) this.member; ReflectionUtils.makeAccessible(method); method.invoke(target, getResourceToInject(target, requestingBeanName)); } catch (InvocationTargetException ex) { throw ex.getTargetException(); } } } ... } } 复制代码
AutowiredAnnotationBeanPostProcessor类中的另外一个重要方法是private AnnotationAttributes findAutowiredAnnotation(AccessibleObject ao)。它经过分析属于一个字段或一个方法的全部注解来查找@Autowired注解。若是未找到@Autowired注解,则返回null,字段或方法也就视为不可注入。
@Nullable 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; } 复制代码
在上面的文章中,咱们看到了Spring中自动注入过程。经过整篇文章能够看到,这种依赖注入是一种便捷易操做方式(能够在字段以及方法上完成),也促使咱们逐渐在抛弃XML配置文件。还加强了代码的可读性。
原文: Spring5源码解析-@Autowired