Spring 5.x 源码之旅三十七之MergedBeanDefinitionPostProcessor扩展点

  • Post author:
  • Post category:其他

图不能少

在这里插入图片描述

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的初始化的过程。

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


版权声明:本文为wangwei19871103原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。