2023-09-16  阅读(243)
原文作者:王伟王胖胖 原文地址: https://blog.csdn.net/wangwei19871103/article/details/105173363

图不能少

202309162313357281.png

applyMergedBeanDefinitionPostProcessors

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

applyBeanPostProcessorsAfterInitialization

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

202309162313365062.png

扩展点实战

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

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

202309162313369803.png
我再改改:

202309162313375004.png
结果:

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

202309162313386776.png

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

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

阅读全文
  • 点赞