Spring依赖注入源码解析

Spring中你要给属性赋值通常有三种方式

        1.@Bean注解中自带的属性@Bean(autowire = Autowire.BY_TYPE/Autowire.BY_NAME)

        2.通过@Autowired/@Resource注解

        3.在Bean实例化完成之后重写postProcessMergedBeanDefinition方法手动为BeanDefinition注入值;

        1.@Bean注解更多的作用是在Spring容器中添加一个Bean,但是如果设置了autowire = Autowire.BY_NAME/Autowire.BY_TYPE这个属性,那么Spring在生成这个Bean的时候会去扫描当前Bean中的set方法,如果是Autowire.BY_NAME,比如是setxxx方法,那么会去singletonObjects(单例池)中找到name = xxx的Bean并将其注入到setxxx方法中的参数中,如果是Autowired.BY_TYPE,那么会解析setxxx(Type1 name1,Type2 name2)中的Type1,Type2的类型,然后根据这两种类型去寻找Bean然后将其注入到name1,name2中,代码如下。


public class AppConfig {

	@Bean(autowire = Autowire.BY_TYPE)
	public UserService userService(){
		return new UserService();
	}
}


public class UserService {

    private OrderService orderService;

    private MyService myService;

    public void test() {
         System.out.println("orderService: "+this.orderService);
        System.out.println("myService: "+this.myService);
    }

    public void setOrderService(OrderService orderService) {
        this.orderService = orderService;
    }

    public void setMyService111(MyService myService) {
        this.myService = myService;
    }
}


public class Test {

	public static void main(String[] args) {

		// 创建一个Spring容器
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

		UserService userService = (UserService) applicationContext.getBean("userService");
		userService.test();
}
}


        可以看出,上述的代码并没有在OrderService和MyService上加@Autowired或者@Resource等注解去注入,但是打印出的结果却不是null,而是有值的,Spring中对应的源码如下,autowireByName方法的逻辑如下->根据setxxx方法解析出xxxBeanName,然后从Spring中去找,然后再将其放到MutablePropertyValues中->pvs.add(propertyName, bean);type也是同理,最后会在applyPropertyValues(beanName, mbd, bw, pvs)方法中处理pvs中的值,并且通过这种方式的赋值会覆盖@Autowired注解的赋值,因为这行代码是放在最后的,在这之前会先通过调用AutowiredAnnotationBeanPostProcessor.postProcessProperties方法解析@Autowired注解和CommonAnnotationBeanPostProcessor.postProcessProperties方法解析@Resouce注解,通过这两个BeanPostProcessor来为添加了@Autowired和@Resouce的属性赋值

		if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
			// MutablePropertyValues是PropertyValues具体的实现类
			MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
			// Add property values based on autowire by name if applicable.
			if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
				//遍历属性并将其设置到pvs中去,然后记录在dependencyMap中,这个Bean依赖了某些属性的Bean,但不会将遍历得到的Bean注入
				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;
		}

        2.解析@Autowired注解和@Resource注解来为属性赋值,Spring中分成了四个BeanPostProcessor,其中有一个是InstantiationAwareBeanPostProcessor,每一个Spring的Bean在执行他的生命周期的时候都会调用这些BeanPostProcessor里面的方法,以下是执行和属性赋值相关的逻辑代码,在AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor中的postProcessProperties方法中会处理和@Autowired和@Resource这两注解

for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
				// 这里会调用AutowiredAnnotationBeanPostProcessor的postProcessProperties()方法,会直接给对象中的属性赋值
				// AutowiredAnnotationBeanPostProcessor内部并不会处理pvs,直接返回了
				PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
}

      这边就挑Autowired注解相关的逻辑看一下,主要就是分为两步,第一步是找到注入点(就是加了@Autowired注解的属性和在setxxx方法上加@Autowired注解),并且缓存下来,第二步是给这些注入点注入值,以下是核心的两个方法

//找注入点,加了@Autowired/@Inject/@Value注解的属性和方法
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
//注入值
metadata.inject(bean, beanName, pvs);

    解析注入点的代码如下,这边就拿属性来举个栗子,方法那边其实也是同理,不过有一个桥接,可能比较特殊(这块自己去了解一下,本文不做其他概述),下面的代码就是会去通过反射一个个找当前属性上是否有@Autowired/@Value/@Inject注解,但是会过滤静态属性/方法(你如果是这个Bean是原型Bean,那么你每次都会去创建新的Bean,然后你这个属性也会跟着创建一个新的,这样和静态的原理是相违背的),然后找到了就直接构造成一个注入点,放到一个list中,在方法中也是一样,最终这些注入点都会加到list里面。然后调用inject方法进行属性赋值

			// 遍历targetClass中的所有Field
			ReflectionUtils.doWithLocalFields(targetClass, field -> {
				// field上是否存在@Autowired、@Value、@Inject中的其中一个
				MergedAnnotation<?> ann = findAutowiredAnnotation(field);
				if (ann != null) {
					// static filed不是注入点,不会进行自动注入
					if (Modifier.isStatic(field.getModifiers())) {
						if (logger.isInfoEnabled()) {
							logger.info("Autowired annotation is not supported on static fields: " + field);
						}
						return;
					}

					// 构造注入点
					boolean required = determineRequiredStatus(ann);
					currElements.add(new AutowiredFieldElement(field, required));
				}
			});

        以下是属性注入的核心逻辑,就是通过反射拿到他的field,然后给target的field属性注入getResourceToInject方法返回的值,target就是我们正在创造的Bean,requestingBeanName就是beanName,此方法中会根据你传入的beanName去BeanFactory里面找到唯一的值(这是核心逻辑,但是代码很长)

			if (this.isField) {
				Field field = (Field) this.member;
				ReflectionUtils.makeAccessible(field);
				field.set(target, getResourceToInject(target, requestingBeanName));
			}

        3.在Spring中你可以通过实现MergedBeanDefinitionPostProcessor接口中的postProcessMergedBeanDefinition方法来为正在创建的Bean中的属性手动赋值,使用方法如下,如果你正在创建的Bean中有OrderService这个属性,那么他会为其赋值,这种形式的赋值其实和第一种差不多,都是放到了PropertyValues中,最后调用applyPropertyValues方法解析PropertyValues存放的注入点并且赋值

	public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
		MutablePropertyValues orderService = beanDefinition.getPropertyValues().add("orderService", new OrderService());

	}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值