spring的扩展点总结

扩展点总览

  • 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的动态注入也是通过这个接口实现的

简单模拟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()};
	}
}

总结

在这里插入图片描述

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值