Java

@Autowired使用

构造函数注入

  1. public Class Outer {
  2. private Inner inner;
  3. @Autowired
  4. public Outer(Inner inner) {
  5. this.inner = inner;
  6. }
  7. }

属性注入

  1. public Class Outer {
  2. @Autowired
  3. private Inner inner;
  4. }

方法注入

  1. public Class Outer {
  2. private Inner inner;
  3. public Inner getInner() {
  4. return inner;
  5. }
  6. @Autowired
  7. public void setInner(Inner inner) {
  8. this.inner = inner;
  9. }
  10. }

目前绝大部分的代码都使用第2、第3种。第1种在bean实例化时完成,而第2、第3种的实现原理都是一样的,在属性填充时完成。这里将介绍第二第三种的是实现原理
在开始之前,如果自己设计@Autowired,应该怎么实现?做法还是比较简单的

  • 通过反射查找bean的class下所有注解了**@Autowired**的字段和方法
  • 获取到字段,通过**getBean**(字段)获取到对应bean,然后再通过反射调用field的set将bean注入

    @Autowired源码分析

    AutowiredAnnotationBeanPostProcessor
    该类是@Autowired的具体实现类,先预览一下类方法
    @Autowired 的实现原理 - 图1
    发现实际有机会介入bean的创建操作只有可能是后置处理器,用于后置处理的有3个方法,其中一个过时不用,分别是postProcessMergedBeanDefinitionpostProcessProperties后置处理,再看一下这2个方法的具体代码

    1. public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter
    2. implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {
    3. ...
    4. @Override
    5. public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
    6. // 1. 寻找bean中所有被@Autowired注释的属性,并将属性封装成InjectedElement类型
    7. InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
    8. metadata.checkConfigMembers(beanDefinition);
    9. }
    10. ...
    11. @Override
    12. public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
    13. // 1. 寻找通过@Autowired注解的属性或者方法
    14. InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
    15. try {
    16. // 2. 注入
    17. metadata.inject(bean, beanName, pvs);
    18. } catch (BeanCreationException ex) {
    19. throw ex;
    20. } catch (Throwable ex) {
    21. throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
    22. }
    23. return pvs;
    24. }
    25. ...
    26. }

    跟猜想是一样的,首先先找出所有注解了@Autowired的属性或者方法,然后进行注入,当然postProcessMergedBeanDefinition后置处理器的调用肯定是在postProcessProperties之前的,这里回顾一下spring bean的创建过程。
    2个处理器已用黄色标出
    @Autowired 的实现原理 - 图2

    1、查找所有@Autowired

    ```java // 寻找bean中所有被@Autowired注释的属性,并将属性封装成InjectedElement类型 InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);

private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) { // Fall back to class name as cache key, for backwards compatibility with custom callers. // 获取缓存的key值,一般以beanName做key String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName()); // Quick check on the concurrent map first, with minimal locking. // 从缓存中获取metadata InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey); // 检测metadata是否需要更新 if (InjectionMetadata.needsRefresh(metadata, clazz)) { synchronized (this.injectionMetadataCache) { metadata = this.injectionMetadataCache.get(cacheKey); if (InjectionMetadata.needsRefresh(metadata, clazz)) { if (metadata != null) { metadata.clear(pvs); } // 通过clazz类,查找所有@Autowired的属性或者方法,并封装成InjectionMetadata类型 metadata = buildAutowiringMetadata(clazz); // 将metadata加入缓存 this.injectionMetadataCache.put(cacheKey, metadata); } } } return metadata; }

  1. 可以看到spring依然在用缓存的方式提高性能,继续跟踪核心代码`buildAutowiringMetadata(clazz)`
  2. ```java
  3. private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
  4. // 查看clazz是否有Autowired注解
  5. if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
  6. return InjectionMetadata.EMPTY;
  7. }
  8. // 这里需要注意AutowiredFieldElement,AutowiredMethodElement均继承了InjectionMetadata.InjectedElement
  9. // 因此这个列表是可以保存注解的属性和被注解的方法的
  10. List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
  11. Class<?> targetClass = clazz;
  12. // 1. 通过do while循环,递归的往直接继承的父类寻找@Autowired
  13. do {
  14. final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
  15. // 2. 通过反射,获取所有属性,doWithLocalFields则是循环的对每个属性应用以下匿名方法
  16. ReflectionUtils.doWithLocalFields(targetClass, field -> {
  17. // 判断当前field属性是否含有@Autowired的注解
  18. MergedAnnotation<?> ann = findAutowiredAnnotation(field);
  19. if (ann != null) {
  20. // 返回该属性在类中的修饰符,如果等于static常量,则抛出异常,@Autowired不允许注解在静态属性上
  21. if (Modifier.isStatic(field.getModifiers())) {
  22. if (logger.isInfoEnabled()) {
  23. logger.info("Autowired annotation is not supported on static fields: " + field);
  24. }
  25. return;
  26. }
  27. // @Autowired有required属性,获取required的值,默认为true
  28. boolean required = determineRequiredStatus(ann);
  29. // 3. 将field封装成InjectedElement,并添加到集合中,这里用的是AutowiredFieldElement
  30. currElements.add(new AutowiredFieldElement(field, required));
  31. }
  32. });
  33. // 4. @Autowired可以注解在方法上
  34. ReflectionUtils.doWithLocalMethods(targetClass, method -> {
  35. Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
  36. if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
  37. return;
  38. }
  39. MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
  40. if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
  41. if (Modifier.isStatic(method.getModifiers())) {
  42. if (logger.isInfoEnabled()) {
  43. logger.info("Autowired annotation is not supported on static methods: " + method);
  44. }
  45. return;
  46. }
  47. if (method.getParameterCount() == 0) {
  48. if (logger.isInfoEnabled()) {
  49. logger.info("Autowired annotation should only be used on methods with parameters: " +
  50. method);
  51. }
  52. }
  53. boolean required = determineRequiredStatus(ann);
  54. PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
  55. // 5. 将方法封装成InjectedElement,并添加到集合中,这里用的是AutowiredMethodElement
  56. currElements.add(new AutowiredMethodElement(method, required, pd));
  57. }
  58. });
  59. elements.addAll(0, currElements);
  60. // 返回直接继承的父类
  61. targetClass = targetClass.getSuperclass();
  62. }
  63. // 如果父类不为空则需要把父类的@Autowired属性或方法也找出
  64. while (targetClass != null && targetClass != Object.class);
  65. // 6. new InjectionMetadata(clazz, elements),将找到的所有的待注入属性或方法生成metadata返回
  66. return InjectionMetadata.forElements(elements, clazz);
  67. }
  • 外层 **do … while …** 的循环被用于递归的查找父类的**@Autowired**属性或方法
  • 通过反射的方式获取到所有属性并循环验证每一个属性是否被**@Autowired**注解
  • 将查找到包含**@Autowired**注解的filed封装成**AutowiredFieldElement**,加入到列表中
  • 循环查找在方法上的注解
  • 将找到的方法封装成**AutowiredMethodElement**,并加入列表

这里需要特别强调一点,InjectedElementAutowiredFieldElementAutowiredMethodElement所继承,他们都有各自的inject函数,实现各自的注入。因此改ArrayList elements是拥有2种类型的属性
@Autowired 的实现原理 - 图3

  • 将找到的所有元素列表和clazz作为参数生成metadata数据返回

    2、注入

    ```java // 注入 metadata.inject(bean, beanName, pvs);

public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable { // 获取所有需要被注入的元素 Collection checkedElements = this.checkedElements; Collection elementsToIterate = (checkedElements != null ? checkedElements : this.injectedElements); // 迭代的元素不为空 if (!elementsToIterate.isEmpty()) { for (InjectedElement element : elementsToIterate) { if (logger.isTraceEnabled()) { logger.trace(“Processing injected element of bean ‘“ + beanName + “‘: “ + element); } // 循环注入,这里有可能是AutowiredFieldElement也可能AutowiredMethodElement,因此调用的inject是2个不同的方法 element.inject(target, beanName, pvs); } } }

  1. 利用for循环,遍历刚刚查到到的elements列表,进行注入。<br />在上面有特别提醒,这里的element有可能是`AutowiredFieldElement`类型、或`AutowiredMethodElement`类型。各自代表`@Autowired`注解在属性上、以及注解在方法上的2种不同元素。因此他们调用的`element.inject(target, beanName, pvs);`也是不一样的
  2. <a name="n00T1"></a>
  3. #### 2.1 字段注入(`AutowiredFieldElement`)
  4. ```java
  5. private class AutowiredFieldElement extends InjectionMetadata.InjectedElement {
  6. @Override
  7. protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
  8. Field field = (Field) this.member;
  9. Object value;
  10. if (this.cached) {
  11. value = resolvedCachedArgument(beanName, this.cachedFieldValue);
  12. }
  13. else {
  14. // 专门用于注入的包装类,包装构造函数参数,方法参数或字段
  15. DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
  16. // 设置class
  17. desc.setContainingClass(bean.getClass());
  18. // 需要被自动注入的beanNames,这里只有可能 = 1,方法注入时才有可能为多个
  19. Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
  20. Assert.state(beanFactory != null, "No BeanFactory available");
  21. TypeConverter typeConverter = beanFactory.getTypeConverter();// 获取类型转换器
  22. try {
  23. // 通过beanFactory获取属性对应的值,比如需要调用getBean("b")获取依赖的属性单例,并且通过自动转型转为需要的类型
  24. value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
  25. }
  26. catch (BeansException ex) {
  27. throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
  28. }
  29. synchronized (this) {
  30. if (!this.cached) {
  31. if (value != null || this.required) {
  32. this.cachedFieldValue = desc;
  33. // 注册依赖,
  34. registerDependentBeans(beanName, autowiredBeanNames);
  35. // 因为是属性注入,因此这里只有可能等于1
  36. if (autowiredBeanNames.size() == 1) {
  37. String autowiredBeanName = autowiredBeanNames.iterator().next();
  38. if (beanFactory.containsBean(autowiredBeanName) &&
  39. beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
  40. // 缓存当前value
  41. this.cachedFieldValue = new ShortcutDependencyDescriptor(
  42. desc, autowiredBeanName, field.getType());
  43. }
  44. }
  45. }
  46. else {
  47. this.cachedFieldValue = null;
  48. }
  49. this.cached = true;
  50. }
  51. }
  52. }
  53. if (value != null) {
  54. // 通过反射,将value值设置到bean中
  55. ReflectionUtils.makeAccessible(field);
  56. field.set(bean, value);
  57. }
  58. }
  59. }

上方大部分的工作都在做待注入bean的获取以及类型的转换,如果深究下去可以再把spring Ioc讲一遍,但是核心还是getBean(字段)获取到对应bean…这里就关心核心的语句,就是这2句

  1. if (value != null) {
  2. // 通过反射,将value值设置到bean中
  3. ReflectionUtils.makeAccessible(field);
  4. field.set(bean, value);
  5. }

spring通过反射的方式,调用field的set进行属性的注入

2.2 方法注入(AutowiredMethodElement)

  1. private class AutowiredMethodElement extends InjectionMetadata.InjectedElement {
  2. @Override
  3. protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
  4. if (checkPropertySkipping(pvs)) {
  5. return;
  6. }
  7. // @Autowired标注在方法上
  8. Method method = (Method) this.member;
  9. Object[] arguments;
  10. if (this.cached) {
  11. // Shortcut for avoiding synchronization...
  12. // 有缓存
  13. arguments = resolveCachedArguments(beanName);
  14. }
  15. else {
  16. // 没缓存,直接获取方法上所有的参数
  17. int argumentCount = method.getParameterCount();
  18. arguments = new Object[argumentCount];
  19. DependencyDescriptor[] descriptors = new DependencyDescriptor[argumentCount];
  20. Set<String> autowiredBeans = new LinkedHashSet<>(argumentCount);
  21. Assert.state(beanFactory != null, "No BeanFactory available");
  22. TypeConverter typeConverter = beanFactory.getTypeConverter();
  23. // 循环所有参数
  24. for (int i = 0; i < arguments.length; i++) {
  25. MethodParameter methodParam = new MethodParameter(method, i);
  26. DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
  27. currDesc.setContainingClass(bean.getClass());
  28. descriptors[i] = currDesc;
  29. try {
  30. // 通过beanFactory,获取代注入的bean,并进行类型转换
  31. Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
  32. if (arg == null && !this.required) {
  33. arguments = null;
  34. break;
  35. }
  36. arguments[i] = arg;
  37. }
  38. catch (BeansException ex) {
  39. throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex);
  40. }
  41. }
  42. synchronized (this) {
  43. if (!this.cached) {
  44. if (arguments != null) {
  45. DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, arguments.length);
  46. // 注册依赖
  47. registerDependentBeans(beanName, autowiredBeans);
  48. // 如果自动注入的个数 = 参数个数,则缓存
  49. if (autowiredBeans.size() == argumentCount) {
  50. Iterator<String> it = autowiredBeans.iterator();
  51. Class<?>[] paramTypes = method.getParameterTypes();
  52. for (int i = 0; i < paramTypes.length; i++) {
  53. String autowiredBeanName = it.next();
  54. if (beanFactory.containsBean(autowiredBeanName) &&
  55. beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
  56. // 缓存
  57. cachedMethodArguments[i] = new ShortcutDependencyDescriptor(
  58. descriptors[i], autowiredBeanName, paramTypes[i]);
  59. }
  60. }
  61. }
  62. // 缓存方法
  63. this.cachedMethodArguments = cachedMethodArguments;
  64. }
  65. else {
  66. this.cachedMethodArguments = null;
  67. }
  68. this.cached = true;
  69. }
  70. }
  71. }
  72. if (arguments != null) {
  73. try {
  74. // 反射调用注入方法,将获取到的所有bean作为参数
  75. ReflectionUtils.makeAccessible(method);
  76. method.invoke(bean, arguments);
  77. }
  78. catch (InvocationTargetException ex) {
  79. throw ex.getTargetException();
  80. }
  81. }
  82. }
  83. }

这里与属性注入最大的区别在于,@Autowired注解在方法上,方法可以拥有多个参数,因此这里需要通过循环将一个个获取,而获取bean的方式于上面一样,本质都是通过getBean获取。
而核心语句还是2句

  1. // 反射调用注入方法,将获取到的所有bean作为参数
  2. ReflectionUtils.makeAccessible(method);
  3. method.invoke(bean, arguments);

与属性注入不同的是,当@Autowired注解在方法上,例如注解在setter方法上,则只需要直接调用该setter方法将参数数组传入即可以,即使用invoke触发方法,具体属性赋值的过程在setter方法中由用户自行编写。