• 如何在Spring框架上做开发之Context启动中的“Hook”


    1.概述

    有些时候,我们需要在spring启动过程中加入一些自己的逻辑,特别是一些基本框架和spring做整合的时候(例如:mybatis-spring-boot-starter),就需要使用Spring给我们预留的扩展接口。本文将介绍3个常用的初始化扩展接口:

    2.spring初始化

    下图是spring启动中,初始化ApplicationContext的3个基本步骤
    Spring在初始化每个阶段都提供了一些“Hook”,提供给开发者进行扩展(开闭原则)

    3.Hook

    3.1 BeanFactoryPostProcessor

    public interface BeanFactoryPostProcessor {
    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
    }
    在ApplicationContext中BeanFactory所有的Bean 的定义已经加载完成,但还未实例化,这个时候可以使用该接口对Bean的属性进行覆盖和设置。

    简单的例子:修改Bean的属性

    @Component
    public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
     
        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory             beanFactory) throws BeansException {
        BeanDefinition myService = beanFactory.getBeanDefinition("myService");
        myService.getPropertyValues().add("name", "Lizo");
        }
    }

    使用方法:

    在BeanFactory中新增(或修改既有的)BeanDefinition,例如
    mockito创建mockBean

    3.2 BeanPostProcessor

    public interface BeanPostProcessor {
        Object postProcessBeforeInitialization(Object bean, String beanName) throws     BeansException;
        Object postProcessAfterInitialization(Object bean, String beanName) throws     BeansException;
    }
    该接口的作用是在Bean创建对象以后,在bean初始化前后提供回调方法,做一些定制化处理(例如包装成代理对象,bean对象注解处理)。
    spring中大量存在BeanPostProcessor的实现类,来完成特定逻辑,下面只是一个简单的例子

    简单例子:对@Service注解的Bean,打印当前BeanName

    @Component
    public class MyBeanPostProcessor implements BeanPostProcessor {
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            return bean;
        }
    
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            Service annotation = AnnotationUtils.findAnnotation(bean.getClass(), Service.class);
            if (annotation != null) {
                System.out.println(beanName);
            }
            return bean;
        }
    }

    使用方法:

    1.Dubbo中远程调用代理类
    2.@PostConstruct注解处理

    和InitializingBean,@PostConstruct,XxxAware的执行顺序

    XxxAware 类似ApplicationContextAware

    3.3 ApplicationListener

    public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
        void onApplicationEvent(E event);
    }
    如果是BeanPostProcessor是在Bean初始化前后提供回调,那ApplicationListener就是在ApplicationContext的启动不同阶段提供回调。
    根据监听的事件ApplicationEvent来完成回调。常用的事件:
    其中可能用的最多的就是ContextRefreshedEvent这个时间。例如有些逻辑要放在整个ApplicationContext完全初始完成之后再执行。

    简单例子:ApplicationContext初始完后,把所有BeanPostProcessor实现类设置为null

    @Component
    public class MyApplicationListener implements ApplicationListener<ContextRefreshedEvent> {
        @Override
        public void onApplicationEvent(ContextRefreshedEvent event) {
            ApplicationContext applicationContext = event.getApplicationContext();
            Map<String, BeanPostProcessor> beansOfType = applicationContext.getBeansOfType(BeanPostProcessor.class);
            beansOfType.forEach((k,v)->{
                v = null;
            });
        }
    }
     

    4.小结

    以上3个是Spring中对Bean进行扩展的常用接口,可以通过这些接口新增,修改,代理,校验等逻辑在spring初始化过程中运行。
     
     

  • 相关阅读:
    分布式事务04JTA+Atomikos
    【二】认识一下鱼缸里四个阶段的水质
    【三】鱼爷到家如何接驾(漫画版)?正确放鱼5步曲……
    【一】【干货】7个养鱼路上的灾难,32条应急挽救+避免办法
    Elasticsearch使用系列Docker搭建Elasticsearch集群
    Elasticsearch使用系列ES简介和环境搭建
    .Net Core(.NET6)中接入Log4net和NLog进行日志记录
    Elasticsearch使用系列基本查询和聚合查询+sql插件
    .Net Core中无处不在的Async/Await是如何提升性能的?
    Elasticsearch使用系列.NET6对接Elasticsearch
  • 原文地址:https://www.cnblogs.com/lizo/p/8259345.html
Copyright © 2020-2023  润新知