前文:通过Spring专题和Mybatis专题,我们学习到了Spring容器在初始化的时候有很多可以利用的机会。我们本篇主要讲解一下几个重要的接口和类,让我们能够在项目中Spring容器初始化的时候,更好的实现我们的需求开发。
一、本篇介绍的接口和类。
1、BeanPostProsessor Bean后置处理器。
2、BeanDefinitionRegistryPostProsessor 动态注册Bean到Spring容器。
3、BeanFactoryPostProsessor bean工厂后置处理器。
4、InitializingBean bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是继承该接口的类,在初始化bean的时候都会执行该方法。
5、ApplicationListener 事件监听器。
6、ImportBeanDefinitionRegistrar ImportBeanDefinitionRegistrar类只能通过其他类@Import的方式来加载,通常是启动类或配置类。
二、对上面的接口和类仅以逐一解析。
1、BeanPostProsessor
public interface BeanPostProcessor {
//在初始化之前调用
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
//在初始化之后调用
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
如果这个接口的某个实现类被注册到某个容器,那么该容器的每个Bean在调用初始化方法之前,都会获得该接口实现类的一个回调。容器调用接口定义的方法时会将该受管Bean的实例和名字通过参数传入方法,进过处理后通过方法的返回值返回给容器。也就是回调了***postProcessBeforeInitialization*** 方法
要使用BeanPostProcessor回调,就必须先在容器中注册实现该接口的类,那么如何注册呢?BeanFactory和ApplicationContext容器的注册方式不大一样:若使用BeanFactory,则必须要显示的调用其addBeanPostProcessor()方法进行注册,参数为BeanPostProcessor实现类的实例;如果是使用ApplicationContext,那么容器会在配置文件在中自动寻找实现了BeanPostProcessor接口的Bean,然后自动注册,我们要做的只是配置一个BeanPostProcessor实现类的Bean就可以了。
我们来看下ApplicationContext容器是怎样注册BeanPostProcessor的。
AbstractApplicationContext中的refresh方法中有一个registerBeanPostProcessors方法。源代码如下
@Override
public void refresh() throws BeansException, IllegalStateException {
//省略....
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
//省略....
/**
* 1.实例化剩余的所有非延迟加载单例对象
* 2.为什么说是剩余的?因为在上面的registerBeanPostProcessors中已经把所有BeanPostProcessors所有对象都已经实例化过了;
* 3.这加载的时候会判断bean是不是 FactoryBean类型的
* 3.1如果是FactoryBean类型,则getBean(&beanName),这里是把FactoryBean本身的对象给实例化了,而没有调它的getObject方法;
* 3.1.1 还要判断是不是SmartFactoryBean类型的,SmartFactoryBean继承了FactoryBean接口;但是它多了一个 boolean isEagerInit();方法;这个方法就是判断是否需要通过FactoryBean的getObject()生成实例;
* 3.2如果不是FactoryBean类型,直接getBean就行了;
* 其实我们在上一篇分享 FactoryBean的时候,有调用BeanPostProcessors的后置方法,但是很不理解这里为啥还要执行一次,因为讲道理在之前就应该执行过,TODO...看文章....
* 4.还要判断是不是SmartInitializingSingleton接口,这个接口有个afterSingletonsInstantiated方法;
* 循环所以bean判断是不是这个类型的,只要是这个类型就调用afterSingletonsInstantiated方法;
*/
finishBeanFactoryInitialization(beanFactory);
//省略..
}
委托给PostProcessorRegistrationDelegate调用其registerBeanPostProcessors方法。按照实现priorityOrdered、Ordered 和其他的顺讯进行回调方法的调用。
2、BeanDefinitionRegistryPostProcessor
调用时机是:invokeBeanFactoryPostProcessors。
invokeBeanFactoryPostProcessors(beanFactory)实际上是委托org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());方法处理的。
所有实现了BeanDefinitionRegistryPostProcessor接口的bean,其postProcessBeanDefinitionRegistry方法都会调用,然后再调用其postProcessBeanFactory方法,这样一来,我们如果自定义了BeanDefinitionRegistryPostProcessor接口的实现类,那么我们开发的postProcessBeanDefinitionRegistry和postProcessBeanFactory方法都会被执行一次;
BeanDefinitionRegistryPostProcessor继承了BeanFactoryPostProcessor接口,BeanFactoryPostProcessor的实现类在其postProcessBeanFactory方法被调用时,可以对bean的定义进行控制,因此BeanDefinitionRegistryPostProcessor的实现类一共要实现以下两个方法:
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException:
该方法的实现中,主要用来对bean定义做一些改变。
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException:
该方法用来注册更多的bean到spring容器中,详细观察入参BeanDefinitionRegistry接口,这个参数可以更改我们bean定义的一些信息。
3、BeanFactoryPostProsessor
BeanFactoryPostProcessor接口与 BeanPostProcessor接口类似,可以对bean的定义(配置元数据)进行处理;也就是spring ioc运行BeanFactoryPostProcessor在容器实例化任何其他的bean之前读取配置元数据,并有可能修改它;如果业务需要,可以配置多个BeanFactoryPostProcessor的实现类,通过”order”控制执行次序(要实现Ordered接口)。
自定义一个实现类:实现bean的定义的信息修改。
/**
* 和BeanPostProcessor原理一致,Spring提供了对BeanFactory进行操作的处理器BeanFactoryProcessor,简单来说就是获取容器BeanFactory,这样就可以在真正初始化bean之前对bean做一些处理操作。
* 允许我们在工厂里所有的bean被加载进来后但是还没初始化前,对所有bean的属性进行修改也可以add属性值。
* **/
@Component
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor{
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// TODO Auto-generated method stub
System.out.println("postProcessBeanFactory");
//获取BeanDefinition
/* TestService testService = (TestService) beanFactory.getBean("testServiceImpl");
//System.out.println("得到 testService ");
testService.doMessage(); */
BeanDefinition beanDefinition = beanFactory.getBeanDefinition("myTestBean");
System.out.println("修改属性name值");
beanDefinition.getPropertyValues().add("name", "liSi");
}
}
执行时机是:refresh()==》invokeBeanFactoryPostProcessors(beanFactory);
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 省略部分代码
postProcessBeanFactory(beanFactory);
invokeBeanFactoryPostProcessors(beanFactory);
// 省略部分代码
}
}
4、InitializingBean
InitializingBean接口为bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是继承该接口的类,在初始化bean的时候都会执行该方法。
import org.springframework.beans.factory.InitializingBean;
@Component
public class TestInitializingBean implements InitializingBean{
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("ceshi InitializingBean");
}
public void testInit(){
System.out.println("ceshi init-method");
}
}
Spring为bean提供了两种初始化bean的方式,实现InitializingBean接口,实现afterPropertiesSet方法,或者在配置文件中通过init-method指定,两种方式可以同时使用。
这里调用时机:
AbstractAutowireCapableBeanFactory==》doCreateBean()==》initializeBean()=>invokeInitMethods()。
5、ApplicationListener
ApplicationListener是Spring事件机制的一部分,与抽象类ApplicationEvent类配合来完成ApplicationContext的事件机制。
如果容器中存在ApplicationListener的Bean,当ApplicationContext调用publishEvent方法时,对应的Bean会被触发。这一过程是典型的观察者模式的实现。
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
/**
* Handle an application event.
* @param event the event to respond to
*/
void onApplicationEvent(E event);
}
6、ImportBeanDefinitionRegistrar
Spring官方通过ImportBeanDefinitionRegistrar实现了 Bean 的动态注入。
很多三方框架集成Spring的时候,都会通过该接口,实现扫描指定的类,然后注册到spring容器中。 比如Mybatis中的Mapper接口,springCloud中的FeignClient接口,都是通过该接口实现的自定义注册逻辑。
public interface ImportBeanDefinitionRegistrar {
void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);
}
自定义ImportBeanDefinitionRegistrar实现类手动注册bean。
public class HelloImportBeanDefinitionRegistrar
implements ImportBeanDefinitionRegistrar {
/**
* @Description AnnotationMetadata:当前类的注解信息;
* BeanDefinitionRegistry:注册类,其registerBeanDefinition()可以注册bean
* @return void
**/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
//扫描注解
Map<String, Object> annotationAttributes = importingClassMetadata
.getAnnotationAttributes(ComponentScan.class.getName());
String[] basePackages = (String[]) annotationAttributes.get("basePackages");
//扫描类
ClassPathBeanDefinitionScanner scanner =
new ClassPathBeanDefinitionScanner(registry, false);
TypeFilter helloServiceFilter = new AssignableTypeFilter(HelloService.class);
scanner.addIncludeFilter(helloServiceFilter);
scanner.scan(basePackages);
}
}
@Configuration
@ComponentScan("com.haien.import2.domain")
@Import(HelloImportBeanDefinitionRegistrar.class)
public class HelloConfiguration {
}
三、总结。
以上这些都是Spring常用的扩展类接口和底层运行逻辑,我们可以利用这些扩展接口来让我们参与Spring容器的初始化和bean的生命周期。