37、Spring5.x源码之旅三十七之MergedBeanDefinitionPostProcessor扩展点

  • 图不能少
  • applyMergedBeanDefinitionPostProcessors
  • applyBeanPostProcessorsAfterInitialization
  • 扩展点实战
    • MyAnnotation注解
  • MyMergedBean
  • MyMergedBeanDefinitionPostProcessor 处理器
  • 测试类

图不能少

*

applyMergedBeanDefinitionPostProcessors

在实例化之后,合并bean定义,其实就是更新bean定义啦,这里可以再次修改bean定义,这里只能修改RootBeanDefinition类型的。前面说过了,主要还是InitDestroyAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessorAutowiredAnnotationBeanPostProcessor处理有注入注解的属性或者方法。分别去处理生命周期PostConstructPreDestroy注解,Resource,WebServiceRef,EJB注解AutowiredValue注解。

applyBeanPostProcessorsAfterInitialization

其实这个可以和上面那个配合,比如上面那个做一些处理,这个后面就可以用,我们下面来做简单的子类看看。
*

扩展点实战

我想定义一个注解,注解上有个属性,就是要打印方法的次数,我希望能找到所有这个属性定义的方法,然后打印他们。

MyAnnotation注解

属性count就是打印的次数。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
   
     
    int count() default 0;
}

MyMergedBean

我们注解一些方法, 看看他会不会打印。

@Component
public class MyMergedBean {
   
     

    @MyAnnotation(count = 1)
    public void m1(String msg) {
   
     
        print(msg);
    }

    @MyAnnotation(count = 2)
    public void m2(String msg) {
   
     
        print(msg);
    }

    @MyAnnotation()
    public void m3(String msg) {
   
     
        print(msg);
    }

    private void print(String msg) {
   
     
        System.out.println(msg);
    }
}

MyMergedBeanDefinitionPostProcessor 处理器

这里主要是实现了postProcessMergedBeanDefinition,做了实例化之后的处理,然后在初始化后postProcessBeforeInitialization具体进行处理。主要是打印有注解的方法,根据注解的属性。

@Component
public class MyMergedBeanDefinitionPostProcessor implements MergedBeanDefinitionPostProcessor {
   
     

    //bean名字对应的注解方法
    public Map<String,List<Method>> stringMethodMap;

    @Nullable
    private Class<? extends Annotation> myAnnotationType;

    public MyMergedBeanDefinitionPostProcessor(){
   
     
        myAnnotationType=MyAnnotation.class;
        stringMethodMap=new HashMap<>();

    }

    @Override
    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
   
     
        List<Method> list=new ArrayList<>();
        ReflectionUtils.doWithLocalMethods(beanType, method -> {
   
     
            if (this.myAnnotationType != null && method.isAnnotationPresent(this.myAnnotationType)) {
   
     
                list.add(method);
                stringMethodMap.put(beanName,list);
            }
        });
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
   
     
        if(stringMethodMap.get(beanName)!=null){
   
     
            for (Method method : stringMethodMap.get(beanName)) {
   
     
                try {
   
     
                    MyAnnotation annotation = (MyAnnotation) method.getAnnotation(this.myAnnotationType);
                    for (int i = 0; i < annotation.count(); i++) {
   
     
                        method.invoke(bean,new Object[]{
   
     method.getName()});
                    }

                } catch (IllegalAccessException e) {
   
     
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
   
     
                    e.printStackTrace();
                }
            }
        }

        return bean;
    }
}

测试类

   @Test
    public void MergedBeanDefinitionPostProcessorTest() throws Exception {
   
     
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(MyConfig.class);
        applicationContext.refresh();

    }

*
我再改改:
*
结果:
*
为什么不是按定义顺序执行呢,好像是因为JDK反射拿出来就是无序的,如果要有序可以用CGLIBClassVisitor来拿,具体spring源码里有,可以参考ConfigurationClassParserretrieveBeanMethodMetadata
*

好了,MyMergedBeanDefinitionPostProcessor到底有什么用呢,就看你的业务啦,只要你想在实例化后做扩展,就可以尝试用这个,参与bean的初始化的过程。

好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵。