leisurexi’s blog资料

本文主要介绍leisurexi’s blog资料 方法和在新技术下所面对的“挑战”,方便大家深入理解leisurexi’s blog资料 过程。本文也将分享leisurexi’s blog资料 所遇到的问题和应对策略,怎么解决怎么做的问题。
通过深入本文可以理解代码原理,进行代码文档的下载,也可以查看相应 Demo 部署效果。

前言

本系列全部基于 Spring 5.2.2.BUILD-SNAPSHOT 版本。因为 Spring 整个体系太过于庞大,所以只会进行关键部分的源码解析。

什么是公共注解?公共注解就是常见的Java注解,特别是JSR-250中的注解。例如:@Resource@PostConstructor@PreDestroy 等等,本文也就主要分析这三个注解在 Spring 中是如何处理的。

正文

@Resource 注解的处理

@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));     }          // 省略其他代码...      } 

BeanDefinition 合并后的后置处理

CommonAnnotationBeanPostProcessor#postProcessMergedBeanDefinition

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 注解详解一文中该方法的详解。

bean 属性后置处理

CommonAnnotationBeanPostProcessor#postProcessProperties

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);         }     } } 

元素注入

InjectionMetadata#inject
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();         }     } } 

获取注入资源

ResourceElement#getResourceToInject
protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {     return (this.lazyLookup ? buildLazyResourceProxy(this, requestingBeanName) : getResource(this, requestingBeanName)); } 

上面的 lazyLookup 就是是否在属性或方法上标注了 @Lazy 注解,该注解先暂不讨论,所以调用后面的 getResource() 方法。

CommonAnnotationBeanPostProcessor#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 的创建一文中分析过,按名称查找 beanresolveBeanByName() 方法实际就是调用 getBean() 通过名称和类型去获取 bean

从上面的代码也可以看出一般情况下 @Resource 注解是按名称注入;而 @Autowired 注解时按类型注入,具体可以查看Spring IoC @Autowired 注解详解。

@PostConstruct、@PreDestroy 注解的处理

处理 @PostConstruct@PreDestroy 注解的处理类是 InitDestroyAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessor 继承与该类,相当于注册 CommonAnnotationBeanPostProcessor 时也注册了 InitDestroyAnnotationBeanPostProcessor

BeanDefinition 合并后的后置处理

InitDestroyAnnotationBeanPostProcessor#postProcessMergedBeanDefinition() 方法是通过 CommonAnnotationBeanPostProcessor#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); } 

InitDestroyAnnotationBeanPostProcessor#postProcessMergedBeanDefinition

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;  	// 省略其它代码... } 

bean 的初始化前回调

InitDestroyAnnotationBeanPostProcessor#postProcessBeforeInitialization

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 的初始化一文。

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;     }  } 

InitDestroyAnnotationBeanPostProcessor#postProcessBeforeDestruction

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。

leisurexi’s blog资料部分资料来自网络,侵权毕设源码联系删除

区块链毕设网(www.qklbishe.com)全网最靠谱的原创区块链毕设代做网站
部分资料来自网络,侵权联系删除!
资源收费仅为搬运整理打赏费用,用户自愿支付 !
qklbishe.com区块链毕设代做网专注|以太坊fabric-计算机|java|毕业设计|代做平台 » leisurexi’s blog资料

提供最优质的资源集合

立即查看 了解详情