04-spring AutowiredAnnotationBeanPostProcessor

04-spring @Autowired和@Value原理

一、MergedBeanDefinitionPostProcessor接口

  • MergedBeanDefinitionPostProcessor接口是BeanPostProcessor的一个子接口,该接口增加了一个方法,该方法在合并处理Bean定义的时候会调用,接口代码
    如下和自己翻译后的注释如下。
public interface MergedBeanDefinitionPostProcessor extends BeanPostProcessor {
    /**
    *这是运行时期合并bean定义信息的的后处理器回调接口,BeanPoseProcessor的实现者可以实现这个子接口来后处理合并的bean定义信息,
    *这些bean定义信息是spring的BeanFactory用来创建bean实例的,合并的bean定义信息是原始bean定义信息的处理后的拷贝。
    *postProcessMergedBeanDefinition方法可以内省一些bean的定义信息,在后置处理器实例化bean之前缓存bean的元信息。也可以修改这些
    *元信息,但是只能修改那些实际上被允许修改的属性。本质上讲,这只适应于Ro*otBeanDefinition自身定义的操作,而不适用于基类的属性。
    */
	void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName);
}
  • 接口只定义了一个方法用来在后期处理bean的定义信息。AutowiredAnnotationBeanPostProcessor是MergedBeanDefinitionPostProcessor接口的重要实现类,
    也是@Autowired和@Value功能关键接口。下面我们结合这个接口和它实现类AutowiredAnnotationBeanPostProcessor以及@Autowire,@Value注解来观察这个接口
    的执行时机。

image

二、调试代码

2.1 测试类

@Component
public class TestController {

    @Value("${testName}")
    String testName;

    @Autowired
    TestService testService;

    @Override
    public String toString() {
        return "TestController{" +
                "testName='" + testName + '\'' +
                ", testService=" + testService +
                '}';
    }
}
 
@Component
public class TestService {

    String id = "100";

    public void setId(String id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "TestService{" +
                "id='" + id + '\'' +
                '}';
    }
}

@Configuration
@ComponentScan("com.intellif")
@PropertySource(value = "classpath:/application.properties")
public class MainConfig1 {
}

2.2 配置文件

testName=mopzing

2.3 测试代码

public class Test1 {

    @Test
    public void test01() {
        ApplicationContext app = new AnnotationConfigApplicationContext(MainConfig1.class);

        System.out.println("The beans in the IOC container are listed as follows: ");
        //1.打印IOC容器中所有的 实例对象名称
        String[] names = app.getBeanDefinitionNames();

        for (String name : names) {
            System.out.println(name + " --- " + app.getBean(name));
        }

        ((AnnotationConfigApplicationContext) app).close();
    }
}

2.4 输出

  • 省去了不重要的打印:
mainConfig1 --- com.intellif.config.MainConfig1$$EnhancerBySpringCGLIB$$1c480837@1ffe63b9
testController --- TestController{testName='mopzing', testService=TestService{id='100'}}
testService --- TestService{id='100'}
  • 我们看到,配置通过@Value正常注入到了TestController的testName属性,TestService也通过@Autowire正常注入到了TestController。

三、断点调试

  • 断点1:AbstractAutowireCapableBeanFactory#doCreateBean#553,我们在这里看到下面的代码,打了断点之后,我们debug到这里,可以看到beanName,
    刚开始beanName不是我们的testController,我们可以跳过,直到beanName是testController,我们再跟进applyMergedBeanDefinitionPostProcessors这个方法,
    因为我们在testController里面用到了@Autowire和@Value,我们就想看看里面是怎么处理的。
		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				try {
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); //line553,这里就是调用MergedBeanDefinitionPostProcessor接口的地方,再次打断点
				}
				catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Post-processing of merged bean definition failed", ex);
				}
				mbd.postProcessed = true;
			}
		}

image

  • 断点2:到了testController之后,我们取消断点1,进入applyMergedBeanDefinitionPostProcessors方法,在位置
    AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors#1018设置断点2,我们可以看到有很多MergedBeanDefinitionPostProcessor
    类型的后处理器会轮流处理testController,我们慢慢跳过,直到AutowiredAnnotationBeanPostProcessor出现,然后跟进1020行的postProcessMergedBeanDefinition方法
	protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
		for (BeanPostProcessor bp : getBeanPostProcessors()) { 
			if (bp instanceof MergedBeanDefinitionPostProcessor) {//line 1018 设置断点2,到这里很多MergedBeanDefinitionPostProcessor类型的后处理器会轮
		//流处理testController,我们慢慢跳过,直到AutowiredAnnotationBeanPostProcessor出现
				MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp; 
				bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName); //line 1020
			}
		}
	}

image

  • 跟进postProcessMergedBeanDefinition方法,我们就到了AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition#232行了
    //AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition
	@Override
	public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
		InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
		//这里面会校验这个两个字段,并把这两个字段放到checkedElements这个属性里面去(一个Map)
		metadata.checkConfigMembers(beanDefinition);
	}
	
	//AutowiredAnnotationBeanPostProcessor#findAutowiringMetadata
	private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
		// Fall back to class name as cache key, for backwards compatibility with custom callers.
		String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
		// Quick check on the concurrent map first, with minimal locking.
		//刚开始进来metadata获取的是null
		InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
		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);//跟进这里
					//buildAutowiringMetadata返回的InjectionMetadata对象,会放到injectionMetadataCache这个缓存里面,cacheKey是beanName
					this.injectionMetadataCache.put(cacheKey, metadata);
				}
			}
		}
		return metadata;
	}
	
	//AutowiredAnnotationBeanPostProcessor#buildAutowiringMetadata
	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方法里面会判断这个字段是否包含注解,包含的话后面的currElements集合就会添加进去
			    //AutowiredAnnotationBeanPostProcessor在构造方法初始化的时候就会把@Autowire和@Value这两个注解添加到集合里面方便后面对字段和方法的判断。
				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;
					}
					//判断require是true还是false
					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));
				}
			});

            //到此会加入testName和testController这两个字段
			elements.addAll(0, currElements);
			targetClass = targetClass.getSuperclass();
		}
		while (targetClass != null && targetClass != Object.class);
        //根据需要注入的属性字段,构造一个InjectionMetadata对象,最终这个对象会放到injectionMetadataCache这个缓存里面
		return new InjectionMetadata(clazz, elements);
	}

image

四、属性赋值

  • 然后看属性赋值的地方,属性赋值不在AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors#1018,属性赋值的入口是
    AbstractAutowireCapableBeanFactory#populateBean(beanName, mbd, instanceWrapper) - line578,而属性赋值实际上不是利用的
    MergedBeanDefinitionPostProcessor接口的方法,属性赋值用到的接口是InstantiationAwareBeanPostProcessor,没错,我们的AutowiredAnnotationBeanPostProcessor还实现了这个接口,这个接口是bean初始化前后的回调方法(注意是初始化不是实例化,实例化的环绕回调接口是BeanPostProcessor),利用InstantiationAwareBeanPostProcessor的后置回调方法postProcessPropertyValues在populateBean里赋值,我们看源码。

AbstractAutowireCapableBeanFactory#1348行跟进postProcessPropertyValues方法,就到了
AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues#368行,我们看到刚刚进来的时候这两个字段还是null值,checkedElements是2表示有2个需要注入的字段
image

五、总结

  • AutowiredAnnotationBeanPostProcessor实现了MergedBeanDefinitionPostProcessor接口,在postProcessMergedBeanDefinition方法里面可以修改bean的定义信息,就是在
    这个方法里面处理@Autowire和@Value注解,这个处理过程主要是做字段和方法的扫描,确定哪些字段被注解标记,然后封装相关的信息,便于后面的依赖注入。
  • AutowiredAnnotationBeanPostProcessor同时还间接继承了InstantiationAwareBeanPostProcessor接口,接口的postProcessAfterInstantiation和postProcessPropertyValues方法会在bean的定义信息完成之后,在赋值的入口方法populateBean里面依次调用,就是在postProcessPropertyValues里面将依赖属性和对象进行注入的。
  • 本文其实只对大体流程做了简单分析,对于AutowiredAnnotationBeanPostProcessor内部源码并未进行详细的分析,该接口主要还是在内部框架使用,写代码用的不多,借此了解spring框架内部的运行流程
  • 本文代码行数基于spring的5.0.6-RELEASE版本源码

六、参考

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值