扩展点总览
- BeanPostProcessor
- BeanFactoryPostProcessor
- BeanDefinitionRegistryPostProcessor
- ImportBeanDefinitionRegistrar
- ImpotSelector
各个扩展点的执行顺序和所处时期
回调方法执行顺序如下
BeanDefinitionRegistryPostProcessor→ImpotSelector→ImportBeanDefinitionRegistrar→BeanFactoryPostProcessor→BeanPostProcessor
- BeanDefinitionRegistryPostProcessor
因为是BeanFactoryPostProcessor的子类,所以不仅有自身的方法,还有BeanFactoryPostProcessor的方法,这个方法是在初始化bean工厂时调用的,这个时候还没有将所有bd注册进bean工厂,而它的工作也是对绝大部分bd的注册。
对于这个接口有一个重要的实现类,也是spring内部的实现类,名字是ConfigurationClassPostProcessor,它在spring上下文对象的构造方法中就注册进了bean工厂,它的postProcessBeanDefinitionRegistry方法,也是BeanDefinitionRegistryPostProcessor特有的实现方法完成了对包的扫描并注册和对@Import注解的处理。
- ImpotSelector
这个接口的实现类因为是在@Import中注入的,所以自然这个类的回调方法也在BeanDefinitionRegistryPostProcessor的后调方法中执行的,它也是在初始化bean工厂时期调用的。
这个实现类的回调方法比ImportBeanDefinitionRegistrar会稍微早一点,但是区别只是属于第一个判断而已,几乎同时期实现的。
注意这个时候扫描的类已经注册进了bean工厂。
- ImportBeanDefinitionRegistrar
这个接口的实现类因为是在@Import中注入的,所以自然这个类的回调方法也在BeanDefinitionRegistryPostProcessor的后调方法中执行的,它也是在初始化bean工厂时期调用的。
注意这个时候扫描的类已经注册进了bean工厂。
- BeanFactoryPostProcessor
在初始化完bean工厂的最后,这个时候绝大部分类已经注册进了bean工厂,包括扫描到的和@Import和@Import注入的类。
同时BeanDefinitionRegistryPostProcessor接口中实现的BeanFactoryPostProcessor的后调方法也会调用,不过会在BeanFactoryPostProcessor的实现类之前。
同样是ConfigurationClassPostProcessor实现的BeanFactoryPostProcessor的postProcessBeanFactory方法会对@Configuration类做cglib的动态代理。
- BeanPostProcessor
属于已经实例化的bean时期调用的,具体待补充
实现后置处理器扩展bean(BeanPostProcessor)
可以看到实现了BeanPostProcessor的类有太多太多,也就是说spring自身也通过这个方式扩展bean的生产过程
这里实现了对UserTest对象的简单扩展,这里的方法是直接把bean传给了使用者,所以使用者可以直接对bean进行操作,这也意味着实现这个接口可以插手spring的bean实例化过程
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof UserTest){
System.out.println("postProcessBeforeInitialization");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof UserTest){
System.out.println("postProcessAfterInitialization");
}
return bean;
}
}
public class UserTest {
public UserTest(){
System.out.println("UserTest");
}
@PostConstruct
public void init(){
System.out.println("init");
}
public void test(){
System.out.println("test");
}
}
public static void main(String[] args) {
//采用注解注解配置和javaconfig
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
//通过register这个方法可以直接注册一个对象到spring容器当中(不需要注解)
annotationConfigApplicationContext.register(UserTest.class);
UserTest userTest = annotationConfigApplicationContext.getBean(UserTest.class);
userTest.test();
}
结果执行的顺序如下
UserTest
postProcessBeforeInitialization
init
postProcessAfterInitialization
test
而且这种扩展的类也可以不止一个,那么就有一个顺序的问题,需要通过实现PriorityOrdered接口来排序,那么就需要实现接口的方法getOrder
其中返回的值的大小就决定了这些bean的初始化顺序,越小就表示越前。
@Override
public int getOrder() {
return 101;
}
BeanFactoryPostProcessor
如果说BeanPostProcessor是对bean生成时的扩展,那么BeanFactoryPostProcessor就是对BeanFactory工厂的扩展。
实现BeanPostProcessor可以拿到bean实例对象,而实现BeanFactoryPostProcessor可以拿到BeanFactory,而且此时的BeanFactory是没有对bean进行实例化的,所以可以通过BeanFactory拿到BeanDefinition对象,就可以直接改变BeanDefinition的属性(比如scope属性,将单例改成多例)。
或者直接设置BeanFactory的属性都是可以的
下面通过更改BeanDefinition中的scope属性将userTest的bean从单例变成了多例
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinition userTest = beanFactory.getBeanDefinition("userTest");
String scope = userTest.getScope();
userTest.setScope("prototype");
}
}
public static void main(String[] args) {
//采用注解配置和javaconfig,开启注解
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
//spring认为的使用者自定义的BeanFactoryPostProcessor
//annotationConfigApplicationContext.addBeanFactoryPostProcessor();
//通过register这个方法可以直接注册一个对象到spring容器当中(不需要注解)
annotationConfigApplicationContext.register(SpringConfig.class);
annotationConfigApplicationContext.register(UserTest.class);
annotationConfigApplicationContext.refresh();
UserTest userTest = annotationConfigApplicationContext.getBean(UserTest.class);
UserTest userTest1 = annotationConfigApplicationContext.getBean(UserTest.class);
userTest.test();
System.out.println(userTest.hashCode()+"-----------"+userTest1.hashCode());
}
需要注意的是这个BeanFactoryPostProcessor只能找到refresh方法及之前注册进bean工厂中的BeanDefinition。
像下面这种情况UserTest是在refresh方法之后注册进bean工厂的,所以BeanFactoryPostProcessor是没有找到UserTest的BeanDefinition。
public static void main(String[] args) {
//采用注解配置和javaconfig,开启注解
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
//spring认为的使用者自定义的BeanFactoryPostProcessor
//annotationConfigApplicationContext.addBeanFactoryPostProcessor();
//通过register这个方法可以直接注册一个对象到spring容器当中(不需要注解)
//annotationConfigApplicationContext.register(SpringConfig.class);
annotationConfigApplicationContext.register(UserTest.class);
//annotationConfigApplicationContext.refresh();
UserTest userTest = annotationConfigApplicationContext.getBean(UserTest.class);
UserTest userTest1 = annotationConfigApplicationContext.getBean(UserTest.class);
userTest.test();
System.out.println(userTest.hashCode()+"-----------"+userTest1.hashCode());
}
这是因为实现BeanFactoryPostProcessor接口的对象是在refresh中执行的
如果有多个实现了BeanFactoryPostProcessor接口的对象,可以通过加上@Order注解来实现顺序执行,同样是设置的值越小越先执行
BeanDefinitionRegistryPostProcessor
BeanDefinitionRegistryPostProcessor是BeanFactoryPostProcessor的子类,那么它一定可以实现BeanFactoryPostProcessor的功能,同时它还做了扩展,功能更加强大。
它不仅可以拿到bean工厂,还可以拿到bean工厂的注册器,这样就可以直接向bean工厂种注册一个bean。
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}
ImportBeanDefinitionRegistrar
同样也是spring的扩展点之一,实现这个接口主要可以得到BeanDefinitionRegistry,也就是bean工厂的注册器,可以直接向bean工厂注册bean,准确来说是bd(BeanDefinition)。
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
}
}
mybatis的动态注入也是通过这个接口实现的
ImpotSelector
实现的selectImports方法返回的字符串数组是需要注入的类全名
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
System.out.println(TestImportSelectorBean.class.getName());
return new String[]{TestImportSelectorBean.class.getName()};
}
}