如何在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初始化过程中运行。
 
 

posted @ 2018-01-10 16:33  atheva  阅读(1441)  评论(0编辑  收藏  举报