本系列全部基于 Spring 5.2.2.BUILD-SNAPSHOT
版本。因为 Spring 整个体系太过于庞大,所以只会进行关键部分的源码解析。
什么是公共注解?公共注解就是常见的Java注解,特别是JSR-250中的注解。例如: @Resource
、 @PostConstructor
、 @PreDestroy
等等,本文也就主要分析这三个注解在 Spring 中是如何处理的。
对 @Resource
注解的处理类是 CommonAnnotationBeanPostProcessor
,它通过实现 InstantiationAwareBeanPostProcessor
接口,重写 postProcessProperties()
方法实现对标注了 @Resource
注解的字段或方法的 自动注入
。
InstantiationAwareBeanPostProcessor
接口的详细信息可以查看 Spring IoC bean 的创建
。
关于 CommonAnnotationBeanPostProcessor
这个后置处理器是怎么加入到 beanFactory
中的,我们在 Spring IoC component-scan 节点详解
一文中介绍过主要是通过 AnnotationConfigUtils#registerAnnotationConfigProcessors()
实现的。
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, @Nullable Object source) { // 省略其他代码... // 注册用于处理@Resource、@PostConstructor、@PostDestroy注解的后置处理器 if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)); } // 省略其他代码... }
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) { super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName); // 寻找需要注入的字段或方法,并封装成 InjectionMetadata InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null); // 检查元数据中的注解信息 metadata.checkConfigMembers(beanDefinition); }
上面代码中的 findAutowiringMetadata()
方法就是利用反射遍历类的所有字段和方法,找到标注了 @Resource
注解的,并缓存进 injectionMetadataCache
中。
注意:静态字段和静态方法会过滤掉。
findAutowiringMetadata()
方法基本和 AutowiredAnnotationBeanPostProcessor
中的一致,只是处理的注解不同而已,可以查查看 Spring IoC @Autowired 注解详解
一文中该方法的详解。
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) { // 从injectionMetadataCache缓存中获取需要注入的字段和方法 InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs); try { // 进行注入 metadata.inject(bean, beanName, pvs); } catch (Throwable ex) { throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex); } return pvs; } // InjectMetadata.java public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable { // 获取检查后的元素 Collection<InjectedElement> checkedElements = this.checkedElements; // 如果checkedElements不为空就使用checkedElements,否则使用injectedElements Collection<InjectedElement> elementsToIterate = (checkedElements != null ? checkedElements : this.injectedElements); if (!elementsToIterate.isEmpty()) { // 遍历elementsToIterate for (InjectedElement element : elementsToIterate) { if (logger.isTraceEnabled()) { logger.trace("Processing injected element of bean '" + beanName + "': " + element); } // 进行元素注入,见下文详解 element.inject(target, beanName, pvs); } } }
protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs) throws Throwable { // 如果元素是字段 if (this.isField) { // 强转成Field类型 Field field = (Field) this.member; // 并设置为可访问 ReflectionUtils.makeAccessible(field); // 然后使用反射设置值 field.set(target, getResourceToInject(target, requestingBeanName)); } else { // 检查是否跳过 if (checkPropertySkipping(pvs)) { return; } try { // 强转成Method类型 Method method = (Method) this.member; // 并设置为可访问 ReflectionUtils.makeAccessible(method); // 使用反射调用方法 method.invoke(target, getResourceToInject(target, requestingBeanName)); } catch (InvocationTargetException ex) { throw ex.getTargetException(); } } }
protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) { return (this.lazyLookup ? buildLazyResourceProxy(this, requestingBeanName) : getResource(this, requestingBeanName)); }
上面的 lazyLookup
就是是否在属性或方法上标注了 @Lazy
注解,该注解先暂不讨论,所以调用后面的 getResource()
方法。
protected Object getResource(LookupElement element, @Nullable String requestingBeanName) throws NoSuchBeanDefinitionException { // 省略其它代码... return autowireResource(this.resourceFactory, element, requestingBeanName); } protected Object autowireResource(BeanFactory factory, LookupElement element, @Nullable String requestingBeanName) throws NoSuchBeanDefinitionException { Object resource; Set<String> autowiredBeanNames; String name = element.name; if (factory instanceof AutowireCapableBeanFactory) { AutowireCapableBeanFactory beanFactory = (AutowireCapableBeanFactory) factory; DependencyDescriptor descriptor = element.getDependencyDescriptor(); // 类型匹配(默认为true) && @Resource注解name属性不为空 && 当前beanFactory不包含名称为name的bean if (this.fallbackToDefaultTypeMatch && element.isDefaultName && !factory.containsBean(name)) { autowiredBeanNames = new LinkedHashSet<>(); // 按类型查找bean resource = beanFactory.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames, null); if (resource == null) { throw new NoSuchBeanDefinitionException(element.getLookupType(), "No resolvable resource object"); } } else { // 按名称查找bean resource = beanFactory.resolveBeanByName(name, descriptor); autowiredBeanNames = Collections.singleton(name); } } // 省略其它代码... return resource; }
上面 autowireResource()
方法中按类型查找的 resolveDependency()
方法在 Spring IoC bean 的创建
一文中分析过,按名称查找 bean
的 resolveBeanByName()
方法实际就是调用 getBean()
通过名称和类型去获取 bean
。
从上面的代码也可以看出一般情况下 @Resource
注解是按名称注入;而 @Autowired
注解时按类型注入,具体可以查看 Spring IoC @Autowired 注解详解
。
处理 @PostConstruct
和 @PreDestroy
注解的处理类是 InitDestroyAnnotationBeanPostProcessor
, CommonAnnotationBeanPostProcessor
继承与该类,相当于注册 CommonAnnotationBeanPostProcessor
时也注册了 InitDestroyAnnotationBeanPostProcessor
。
InitDestroyAnnotationBeanPostProcessor#postProcessMergedBeanDefinition()
方法是通过 CommonAnnotationBeanPostProcessor#postProcessMergedBeanDefinition()
方法调用的,如下:
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) { // 调用InitDestroyAnnotationBeanPostProcessor的postProcessMergedBeanDefinition()方法 super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName); // 寻找需要注入的字段或方法,并封装成 InjectionMetadata InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null); // 检查元数据中的注解信息 metadata.checkConfigMembers(beanDefinition); }
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) { // 寻找需要标注了@PostConstruct和@PreDestroy注解的方法,并封装进LifecycleMetadata LifecycleMetadata metadata = findLifecycleMetadata(beanType); // 检查元数据中的注解信息 metadata.checkConfigMembers(beanDefinition); }
上面代码中的 findLifecycleMetadata()
方法,就是遍历当前初始化的 bean
包括其父类中所有标注了 @PostConstruct
和 @PreDestroy
注解的方法,并封装成 LifecycleMetadata
(该类是 InitDestroyAnnotationBeanPostProcessor
中一个内部类),并放入 lifecycleMetadataCache
缓存中。
这里我们简单看一下 LifecycleMetadata
这个类:
private class LifecycleMetadata { // 目标类,也就是当前正在初始化的bean private final Class<?> targetClass; // 存放标注了@PostConstruct的方法 private final Collection<LifecycleElement> initMethods; // 存放标注了@PreDestroy的方法 private final Collection<LifecycleElement> destroyMethods; // 省略其它代码... }
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { // 从lifecycleMetadataCache缓存中获取LifecycleMetadata LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass()); try { // 反射调用所有初始化方法 metadata.invokeInitMethods(bean, beanName); } // 省略异常处理... return bean; }
看到这里我们知道为什么标注了 @PostConstruct
注解的方法比 InitializingBean#afterPropertiesSet()
方法和自定义初始化方法先调用了;因为其在 bean
的初始化前回调就已经调用了,而剩下的两个是在初始化方法中调用的,详情可以查看 Spring IoC bean 的初始化
一文。
我们先了解一下 DestructionAwareBeanPostProcessor
,它继承自 BeanPostProcessor
,如下:
public interface DestructionAwareBeanPostProcessor extends BeanPostProcessor { /** * Bean 销毁前阶段回调 */ void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException; /** * bean实例是否要由此方法销毁 */ default boolean requiresDestruction(Object bean) { return true; } }
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException { // 从lifecycleMetadataCache缓存中获取LifecycleMetadata LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass()); try { // 反射调用所有销毁方法 metadata.invokeDestroyMethods(bean, beanName); } // 省略异常处理... }
和上面的 @PostConstruct
注解一样, @PreDestroy
注解标注的方法也比 DisposableBean#destroy()
方法和自定义销毁方法先调用。
本文主要介绍了 @Resource
、 @PostConstruct
、 @PreDestroy
注解 Spring 是如何对其处理的,可以看出 Spring 的注解驱动大多依靠 实现 BeanPostProcessor
及其子类中的 bean
生命周期各个阶段的回调方法来进行实现的。
最后,我模仿 Spring 写了一个精简版,代码会持续更新。地址: https://github.com/leisurexi/tiny-spring 。