• Spring依赖注入源码解析(上)



    前言

    在看@Autowired注解源码之前,需要先了解一下现有的注入方式,才能更好的理解spring底层实现

    本篇文章主要以**@Autowired寻找注入点、注入点进行注入**重点解析


    一、Spring中到底有几种依赖注入的方式?

    分两种:

    手动注入
    自动注入
    
    • 1
    • 2

    1、手动注入

    在XML中定义Bean时,就是手动注入,因为是程序员手动给某个属性指定了值。

    1.1、set方法进行注入

    <bean name="userService" class="com.luban.service.UserService">
     <property name="orderService" ref="orderService"/>
    bean>
    
    • 1
    • 2
    • 3

    1.2、通过构造方法进行注入

    <bean name="userService" class="com.luban.service.UserService">
     <constructor-arg index="0" ref="orderService"/>
    bean>
    
    • 1
    • 2
    • 3

    所以手动注入的底层也就是分为两种:

    set方法注入
    构造方法注入
    
    • 1
    • 2

    2、自动注入

    自动注入又分为两种

    XML的autowire自动注入
    @Autowired注解的自动注入
    
    • 1
    • 2

    2.1、XML的autowire自动注入

    在XML中,我们可以在定义一个Bean时去指定这个Bean的自动注入模式:

    byType
    byName
    constructor
    default
    no
    
    • 1
    • 2
    • 3
    • 4
    • 5

    比如:

    <bean id="userService" class="com.luban.service.UserService" autowire="byType"/>
    
    
    • 1
    • 2

    这么写,表示Spring会自动的给userService中所有的属性自动赋值(不需要这个属性上有@Autowired注解,但需要这个属性有对应的set方法)。


    2.2、@Autowired注解的自动注入

    @Autowired注解,是byType和byName的结合。

    @Autowired注解可以写在

    属性上:先根据属性类型去找Bean,如果找到多个再根据属性名确定一个
    构造方法上:先根据方法参数类型去找Bean,如果找到多个再根据参数名确定一个
    set方法上:先根据方法参数类型去找Bean,如果找到多个再根据参数名确定一个

    而这种底层用到了:

    属性注入
    set方法注入
    构造方法注入
    
    • 1
    • 2
    • 3

    二、autowireByName && autowireByType核心源码分析

    autowireByName 和autowireByType底层逻辑基本差不多,区别就是一个根据类型,一个根据名称

    if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
    			MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
    			// Add property values based on autowire by name if applicable.
    			if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
    				autowireByName(beanName, mbd, bw, newPvs);
    			}
    			// Add property values based on autowire by type if applicable.
    			if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
    				autowireByType(beanName, mbd, bw, newPvs);
    			}
    			pvs = newPvs;
    		}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2.1、autowireByName

    干了啥?
    遍历beanName属性名,根据属性名getBean,添加到pvs集合中

    protected void autowireByName(
    			String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
    		// 当前Bean中能进行自动注入的属性名
    		String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
    		// 遍历每个属性名,获取getBean并且添加到pvs中
    		for (String propertyName : propertyNames) {
    			if (containsBean(propertyName)) {
    				Object bean = getBean(propertyName);
    				pvs.add(propertyName, bean);
    				// 记录一下当前遍历的Bean被哪个bean依赖了(可以理解为propertyName=orderService,beanName=userService)
    				registerDependentBean(propertyName, beanName);
    				if (logger.isTraceEnabled()) {
    					logger.trace("Added autowiring by name from bean name '" + beanName +
    							"' via property '" + propertyName + "' to bean named '" + propertyName + "'");
    				}
    			}
    			else {
    				if (logger.isTraceEnabled()) {
    					logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName +
    							"' by name: no matching bean found");
    				}
    			}
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    2.2、获取可以依赖注入的beanName----unsatisfiedNonSimpleProperties()

    主要做了几件事情
    1、底层获取PropertyDescriptor对象数组
    2、遍历,筛选到满足可以自动注入的benaName集合,返回

    protected String[] unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd, BeanWrapper bw) {
    		Set<String> result = new TreeSet<>();
    		PropertyValues pvs = mbd.getPropertyValues();
    		// 1、拿到当前类的所有set方法,setxxx,拿到的name就是xxx。
    		PropertyDescriptor[] pds = bw.getPropertyDescriptors();
    		// 2、遍历
    		for (PropertyDescriptor pd : pds) {
    			// 什么样的属性能进行自动注入?
    			// 1.getWriteMethod---该类有对应的set方法
    			// 2.isExcludedFromDependencyCheck --- 忽略自动装配的给定依赖类型:例如,String。默认为none。
    			// 3.pvs.contains(pd.getName())---程序员自己没有给当前属性设置值
    			// 4.!BeanUtils.isSimpleProperty(pd.getPropertyType())---属性类型不是简单类型,比如int、Integer、int[]、Date、Number、URL....
    			if (pd.getWriteMethod() != null && !isExcludedFromDependencyCheck(pd) && !pvs.contains(pd.getName()) &&
    					!BeanUtils.isSimpleProperty(pd.getPropertyType())) {
    				// 把满足注入条件的加入到集合
    				result.add(pd.getName());
    			}
    		}
    		return StringUtils.toStringArray(result);
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20


    三、@Autowired核心源码–AutowiredAnnotationBeanPostProcessor

    for (BeanPostProcessor bp : getBeanPostProcessors()) {
    				if (bp instanceof InstantiationAwareBeanPostProcessor) {
    					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
    					PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
    					if (pvsToUse == null) {
    						if (filteredPds == null) {
    							filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
    						}
    						pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
    						if (pvsToUse == null) {
    							return;
    						}
    					}
    					pvs = pvsToUse;
    				}
    			}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    AutowiredAnnotationBeanPostProcessor实现了上面的InstantiationAwareBeanPostProcessor接口

    在属性填充代码逻辑中,上面这一段代码,会去调用AutowiredAnnotationBeanPostProcessor#postProcessProperties()做处理

    这段代码主要是对bean里面包含了@Autowired注解的属性做处理


    3.1、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;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    3.2、findAutowiringMetadata–找到自动装配元数据(寻找注入点)

    这个方法会有多个地方调用

    第一次调用的地方其实是在Bean后置处理器里面调用applyMergedBeanDefinitionPostProcessors,然后才是在属性填充时调用

    这个方法主要是把类名称添加到缓存里

    private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
    		// 类名作为缓存key
    		String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
    		// 查看缓存里有没有类名key,第一次进来肯定是没有的
    		InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
    		// 为空则进if,双重锁检测
    		if (InjectionMetadata.needsRefresh(metadata, clazz)) {
    			synchronized (this.injectionMetadataCache) {
    				metadata = this.injectionMetadataCache.get(cacheKey);
    				if (InjectionMetadata.needsRefresh(metadata, clazz)) {
    					if (metadata != null) {
    						//清除缓存
    						metadata.clear(pvs);
    					}
    					// 构建自动装配元数据,然后添加到缓存
    					metadata = buildAutowiringMetadata(clazz);
    					this.injectionMetadataCache.put(cacheKey, metadata);
    				}
    			}
    		}
    		return metadata;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    3.3、buildAutowiringMetadata–构建注入点(核心方法)

    主要做了几件事情
    1、看你这个类型是不是一个基础类型
    2.、遍历当前类下的属性,寻找注入点,看是否有有@Autowired & @Value注解的属性
    3、然后确定required状态,然后添加到需要注入的集合里
    4、遍历当前类下的方法,寻找注入点,看是否有有@Autowired & @Value注解的set方法
    5、同2一致
    6、while循环,查找父类有没有注入点,直到找到所有的注入点结束

    private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
    		// 检查有没有前缀是不是以"java.开头,如String,Integer等...基础类型,基础类型不会被注入
    		if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
    			return InjectionMetadata.EMPTY;
    		}
    
    		List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
    		Class<?> targetClass = clazz;
    
    		do {
    			final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
    			// 处理当前类下的属性
    			ReflectionUtils.doWithLocalFields(targetClass, field -> {
    				// 有@Autowired & @Value注解的属性
    				MergedAnnotation<?> ann = findAutowiredAnnotation(field);
    				if (ann != null) {
    					// 不是注入点,不会注入
    					if (Modifier.isStatic(field.getModifiers())) {
    						if (logger.isInfoEnabled()) {
    							logger.info("Autowired annotation is not supported on static fields: " + field);
    						}
    						return;
    					}
    					// 判断注解是否包含required,一般情况这里都返回true
    					boolean required = determineRequiredStatus(ann);
    					// 添加到集合(里面包含需要依赖注入的属性)
    					currElements.add(new AutowiredFieldElement(field, required));
    				}
    			});
    
    			// 处理当前类下的method方法
    			ReflectionUtils.doWithLocalMethods(targetClass, method -> {
    				// 查找桥接方法,一般没有自己返回
    				Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
    				if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
    					return;
    				}
    				//  查找是否有@Autowired & @Value注解的方法,
    				MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
    				if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
    					// 不是注入点,不会注入
    					if (Modifier.isStatic(method.getModifiers())) {
    						if (logger.isInfoEnabled()) {
    							logger.info("Autowired annotation is not supported on static methods: " + method);
    						}
    						return;
    					}
    					// 如果没有构造参数,则打印日志
    					if (method.getParameterCount() == 0) {
    						if (logger.isInfoEnabled()) {
    							logger.info("Autowired annotation should only be used on methods with parameters: " +
    									method);
    						}
    					}
    					//  判断注解是否包含required,一般情况这里都返回true
    					boolean required = determineRequiredStatus(ann);
    					// 
    					PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
    					// 添加到需要依赖注入的集合里
    					currElements.add(new AutowiredMethodElement(method, required, pd));
    				}
    			});
    			// 添加所有属性和method的需要依赖的bean
    			elements.addAll(0, currElements);
    			// 获取父类
    			targetClass = targetClass.getSuperclass();
    		}
    		// 循环直到没有父类为止,全部添加到一个集合里
    		while (targetClass != null && targetClass != Object.class);
    
    		return InjectionMetadata.forElements(elements, clazz);
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72

    3.4、寻找注入点流程总结

    在创建一个Bean的过程中,Spring会利用AutowiredAnnotationBeanPostProcessor的postProcessMergedBeanDefinition()找出注入点并缓存,找注入点的流程为

    1、遍历当前类的所有的属性字段Field

    2、查看字段上是否存在@Autowired、@Value、@Inject中的其中任意一个,存在则认为该字段是一个注入点

    3、如果字段是static的,则不进行注入

    4、获取@Autowired中的required属性的值

    5、将字段信息构造成一个AutowiredFieldElement对象,作为一个注入点对象添加到currElements集合中。

    6、遍历当前类的所有方法Method

    7、判断当前Method是否是桥接方法,如果是找到原方法

    8、查看方法上是否存在@Autowired、@Value、@Inject中的其中任意一个,存在则认为该方法是一个注入点

    9、如果方法是static的,则不进行注入

    10、获取@Autowired中的required属性的值

    11、将方法信息构造成一个AutowiredMethodElement对象,作为一个注入点对象添加到currElements集合中。

    12、遍历完当前类的字段和方法后,将遍历父类的,直到没有父类。

    13、最后将currElements集合封装成一个InjectionMetadata对象,作为当前Bean对于的注入点集合对象,并缓存。


    3.5、思考?static的字段或方法为什么不支持

    @Component
    @Scope("prototype")
    public class OrderService {
    
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    @Component
    @Scope("prototype")
    public class UserService  {
    
     @Autowired
     private static OrderService orderService;
    
     public void test() {
      System.out.println("test123");
     }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    看上面代码,UserService和OrderService都是原型Bean,假设Spring支持static字段进行自动注入,那么现在调用两次

    UserService userService1 = (UserService) context.getBean("userService");
    UserService userService2 = (UserService) context.getBean("userService");
    
    • 1
    • 2

    问此时,userService1的orderService值是什么?还是它自己注入的值吗?

    答案是:不是,一旦userService2 创建好了之后,static orderService字段的值就发生了修改了,从而出现bug。


    3.6、上述源码提到的桥接方法是什么?

    public interface UserInterface<T> {
     void setOrderService(T t);
    }
    
    • 1
    • 2
    • 3
    @Component
    public class UserService implements UserInterface<OrderService> {
    
     private OrderService orderService;
    
     @Override
     @Autowired
     public void setOrderService(OrderService orderService) {
      this.orderService = orderService;
     }
    
     public void test() {
      System.out.println("test123");
     }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    UserService对应的字节码为:

    // class version 52.0 (52)
    // access flags 0x21
    // signature Ljava/lang/Object;Lcom/ljc/service/UserInterface;
    // declaration: com/ljc/service/UserService implements com.ljc.service.UserInterface
    public class com/ljc/service/UserService implements com/ljc/service/UserInterface {
    
      // compiled from: UserService.java
    
      @Lorg/springframework/stereotype/Component;()
    
      // access flags 0x2
      private Lcom/ljc/service/OrderService; orderService
    
      // access flags 0x1
      public <init>()V
       L0
        LINENUMBER 12 L0
        ALOAD 0
        INVOKESPECIAL java/lang/Object.<init> ()V
        RETURN
       L1
        LOCALVARIABLE this Lcom/ljc/service/UserService; L0 L1 0
        MAXSTACK = 1
        MAXLOCALS = 1
    
      // access flags 0x1
      public setOrderService(Lcom/ljc/service/OrderService;)V
      @Lorg/springframework/beans/factory/annotation/Autowired;()
       L0
        LINENUMBER 19 L0
        ALOAD 0
        ALOAD 1
        PUTFIELD com/ljc/service/UserService.orderService : Lcom/ljc/service/OrderService;
       L1
        LINENUMBER 20 L1
        RETURN
       L2
        LOCALVARIABLE this Lcom/ljc/service/UserService; L0 L2 0
        LOCALVARIABLE orderService Lcom/ljc/service/OrderService; L0 L2 1
        MAXSTACK = 2
        MAXLOCALS = 2
    
      // access flags 0x1
      public test()V
       L0
        LINENUMBER 23 L0
        GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
        LDC "test123"
        INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
       L1
        LINENUMBER 24 L1
        RETURN
       L2
        LOCALVARIABLE this Lcom/ljc/service/UserService; L0 L2 0
        MAXSTACK = 2
        MAXLOCALS = 1
    
      // access flags 0x1041
      public synthetic bridge setOrderService(Ljava/lang/Object;)V
      @Lorg/springframework/beans/factory/annotation/Autowired;()
       L0
        LINENUMBER 11 L0
        ALOAD 0
        ALOAD 1
        CHECKCAST com/ljc/service/OrderService
        INVOKEVIRTUAL com/ljc/service/UserService.setOrderService (Lcom/ljc/service/OrderService;)V
        RETURN
       L1
        LOCALVARIABLE this Lcom/ljc/service/UserService; L0 L1 0
        MAXSTACK = 2
        MAXLOCALS = 2
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73

    可以看到在UserSerivce的字节码中有两个setOrderService方法:

    public setOrderService(Lcom/ljc/service/OrderService;)V
    public synthetic bridge setOrderService(Ljava/lang/Object;)V
    
    • 1
    • 2

    并且都是存在@Autowired注解的。

    所以在Spring中需要处理这种情况**,当遍历到桥接方法时,得找到原方法**。


    四、inject-注入(需要重点关注)

    在上一步构建好注入点后,寻找开始依赖注入!

    Spring在AutowiredAnnotationBeanPostProcessor的**postProcessProperties()**方法中,会遍历所找到的注入点依次进行注入。

    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()) {
    			// 遍历每个注入点,开始依赖注入
    			for (InjectedElement element : elementsToIterate) {
    				element.inject(target, beanName, pvs);
    			}
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    需要注意上面的

    element.inject(target, beanName, pvs);
    
    • 1

    并不是直接看父类的实现,在@Autowired实现这里 只需要看 field和method的2个实现即可,@Resource的实现是用的父类实现

    在这里插入图片描述


    4.1、AutowiredFieldElement#inject–字段的注入

    主要做了几件事情
    1、遍历所有的AutowiredFieldElement对象。

    2、将对应的字段封装为DependencyDescriptor对象。

    3、调用BeanFactory的resolveDependency()方法,传入DependencyDescriptor对象,进行依赖查找,找到当前字段所匹配的Bean对象。

    4、将DependencyDescriptor对象和所找到的结果对象beanName封装成一个**ShortcutDependencyDescriptor对象作为缓存,**比如如果当前Bean是原型Bean,那么下次再来创建该Bean时,就可以直接拿缓存的结果对象beanName去BeanFactory中去那bean对象了,不用再次进行查找了

    5、将结果对象赋值给字段。

    @Override
       protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
          Field field = (Field) this.member;
          Object value;
          // 默认是false,第一次进来肯定不会进if
          if (this.cached) {
             value = resolvedCachedArgument(beanName, this.cachedFieldValue);
          }
          else {
          	 // 将对应的字段封装为DependencyDescriptor对象(创建依赖描述符对象)
             DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
             // 设置calss
             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) {
                   Object cachedFieldValue = null;
                   if (value != null || this.required) {
                      cachedFieldValue = desc;
                      registerDependentBeans(beanName, autowiredBeanNames);
                      if (autowiredBeanNames.size() == 1) {
                         String autowiredBeanName = autowiredBeanNames.iterator().next();
                         if (beanFactory.containsBean(autowiredBeanName) &&
                               beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
                            // 创建缓存对象,方便缓存
                            cachedFieldValue = new ShortcutDependencyDescriptor(
                                  desc, autowiredBeanName, field.getType());
                         }
                      }
                   }
                   // 缓存
                   this.cachedFieldValue = cachedFieldValue;
                   this.cached = true;
                }
             }
          }
          if (value != null) {
             ReflectionUtils.makeAccessible(field);
             // 将结果对象赋值给字段
             field.set(bean, value);
          }
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    4.2、AutowiredMethodElement#inject–方法的注入

    和字段注入实现逻辑类似…

    主要做了几件事情
    1、遍历所有的AutowiredMethodElement对象

    2、遍历将对应的方法的参数,将每个参数封装成MethodParameter对象

    3、将MethodParameter对象封装为DependencyDescriptor对象

    4、调用BeanFactory的resolveDependency()方法,传入DependencyDescriptor对象,进行依赖查找,找到当前方法参数所匹配的Bean对象。

    5、将DependencyDescriptor对象和所找到的结果对象beanName封装成一个ShortcutDependencyDescriptor对象作为缓存,比如如果当前Bean是原型Bean,那么下次再来创建该Bean时,就可以直接拿缓存的结果对象beanName去BeanFactory中去那bean对象了,不用再次进行查找了

    6、利用反射将找到的所有结果对象传给当前方法,并执行。

    		@Override
    		protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
    			if (checkPropertySkipping(pvs)) {
    				return;
    			}
    			Method method = (Method) this.member;
    			Object[] arguments;
    			if (this.cached) {
    				// Shortcut for avoiding synchronization...
    				arguments = resolveCachedArguments(beanName);
    			}
    			else {
    				int argumentCount = method.getParameterCount();
    				arguments = new Object[argumentCount];
    				DependencyDescriptor[] descriptors = new DependencyDescriptor[argumentCount];
    				Set<String> autowiredBeans = new LinkedHashSet<>(argumentCount);
    				Assert.state(beanFactory != null, "No BeanFactory available");
    				TypeConverter typeConverter = beanFactory.getTypeConverter();
    				for (int i = 0; i < arguments.length; i++) {
    					// 每个参数封装成MethodParameter对象
    					MethodParameter methodParam = new MethodParameter(method, i);
    					// 将MethodParameter对象封装为DependencyDescriptor对象
    					DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
    					currDesc.setContainingClass(bean.getClass());
    					descriptors[i] = currDesc;
    					try {
    						// 进行依赖查找,找到当前方法参数所匹配的Bean对象
    						Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
    						if (arg == null && !this.required) {
    							arguments = null;
    							break;
    						}
    						arguments[i] = arg;
    					}
    					catch (BeansException ex) {
    						throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex);
    					}
    				}
    				synchronized (this) {
    					if (!this.cached) {
    						if (arguments != null) {
    							DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, arguments.length);
    							registerDependentBeans(beanName, autowiredBeans);
    							if (autowiredBeans.size() == argumentCount) {
    								Iterator<String> it = autowiredBeans.iterator();
    								Class<?>[] paramTypes = method.getParameterTypes();
    								for (int i = 0; i < paramTypes.length; i++) {
    									String autowiredBeanName = it.next();
    									if (beanFactory.containsBean(autowiredBeanName) &&
    											beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
    										// 封装缓存对象
    										cachedMethodArguments[i] = new ShortcutDependencyDescriptor(
    												descriptors[i], autowiredBeanName, paramTypes[i]);
    									}
    								}
    							}
    							this.cachedMethodArguments = cachedMethodArguments;
    						}
    						else {
    							this.cachedMethodArguments = null;
    						}
    						this.cached = true;
    					}
    				}
    			}
    			if (arguments != null) {
    				try {
    					ReflectionUtils.makeAccessible(method);
    					// 注入
    					method.invoke(bean, arguments);
    				}
    				catch (InvocationTargetException ex) {
    					throw ex.getTargetException();
    				}
    			}
    		}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76

  • 相关阅读:
    Java基于springboot公务员招考务信息发布平台#计算机毕业设计
    什么是零日攻击?
    (免费分享)基于springboot论坛bbs系统
    HTML+CSS+JavaScript仿京东购物商城网站 web前端制作服装购物商城 html电商购物网站
    【Leetcode Sheet】Weekly Practice 15
    查看指定 SAP CRM One Order 的 note 数据
    《ON JAVA》学习笔记4:IDE帮我们做的事
    RabbitMQ如何保证顺序性
    java计算机毕业设计个性化穿搭推荐系统MyBatis+系统+LW文档+源码+调试部署
    STM32F4X RTC
  • 原文地址:https://blog.csdn.net/qq_33522097/article/details/127893521