Spring之所以能打败其他所有同类型Java开发框架屹立不倒的重要原因之一就是提供很多扩展点,让其他组件和框架很容易就整合到Spring框架里,所以也就诞生很多基于Spring的二次开发项目,接下来我们一起聊聊Spring提供哪些扩展点,这篇文章只是简单说明扩展点但不深入,有兴趣的伙伴可以后续一起学习交流,本篇最后我们再进行一个Mybatis和Spring整合工程简易开发示例
Spring加载上下文方式Spring加载容器上下文主要提供以下三大类方式,第一种基于配置类为常用的使用方式,AnnotationConfigApplicationContext传入参数是一个Class数组也即是支持多个配置类
public class ApplicationDemo {
public static void main(String[] args) {
//基于配置类加载Spring上下文
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
Student student = applicationContext.getBean(Student.class);
System.out.println(student);
//基于项目路径xml加载Spring上下文
ClassPathXmlApplicationContext applicationContextXml = new ClassPathXmlApplicationContext("spring.xml");
student = applicationContextXml.getBean(Student.class);
System.out.println(student);
//基于文件系统绝对路径xml加载Spring上下文
FileSystemXmlApplicationContext applicationContextFileXml = new FileSystemXmlApplicationContext("E://spring.xml");
student = applicationContextXml.getBean(Student.class);
System.out.println(student);
}
}
@Configuration
@ComponentScan({"com.itxs.pojo","com.itxs.extend"})
public class MyConfig {
}
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
this();
register(componentClasses);
refresh();
}
扩展点ApplicationContextInitializer
这个是Spring Boot提供的扩展点,在整个 spring 容器在刷新之前初始化 ConfigurableApplicationContext 的回调接口,简单来说,就是在容器刷新之前调用此类的 initialize 方法。这个点允许用户自己扩展。用户可以在整个 spring 容器还没被初始化之前做过一些事情。可以想到的场景可能为,在最开始激活一些配置,或者利用这时候 class 还没被类加载器加载的时机,进行动态字节码注入等操作
public class MyApplicationContextInitializer implements ApplicationContextInitializer {
@Override
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
System.out.println("-----------------------MyApplicationContextInitializer initialize");
}
}
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
//SpringApplication Main函数添加初始化器方式
SpringApplication springApplication = new SpringApplication(MyApplication.class);
springApplication.addInitializers(new MyApplicationContextInitializer());
springApplication.run(args);
}
}
第二种配置文件中的配置
context:
initializer:
classes: com.itxs.extend.MyApplicationContextInitializer
第三种SpringBoot的SPI扩展---META-INF/spring.factories中配置
org.springframework.context.ApplicationContextInitializer=com.itxs.extend.MyApplicationContextInitializer
BeanDefinitionRegistryPostProcessor是BeanFactoryPostProcessor的子接口,BeanFactoryPostProcessor的作用是在bean的定义信息已经加载但还没有进行初始化的时候执行postProcessBeanFactory()的方法,BeanDefinitionRegistryPostProcessor是在BeanFactoryPostProcessor的前面执行,在bean定义之后提供的扩展点,比如可以在这里动态注册自己的 beanDefinition,加载 classpath 之外的 bean信息。
@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
System.out.println("BeanDefinitionRegistryPostProcessor-postProcessBeanDefinitionRegistry");
System.out.println("BeanDefinitionCount:" beanDefinitionRegistry.getBeanDefinitionCount());
String[] beanDefinitionNames = beanDefinitionRegistry.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println("beanDefinitionName:" beanDefinitionName);
}
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
System.out.println("BeanDefinitionRegistryPostProcessor-postProcessBeanFactory");
}
}
BeanFactoryPostProcessor-Bean工厂后置处理器
BeanFactoryPostProcessor 接口是 Spring 初始化 BeanFactory 的扩展接口,在 Spring 在读取 beanDefinition 信息之后实例化 bean 之前读取 bean 定义并可以修改它。在这个时机,用户可以通过实现这个扩展接口来自行处理一些东西,比如修改已经注册的 beanDefinition 的元信息。下面将student bean类型修改为teacher bean类型
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
System.out.println("BeanFactoryPostProcessor-postProcessBeanFactory");
BeanDefinition student = configurableListableBeanFactory.getBeanDefinition("student");
student.setBeanClassName(Teacher.class.getName());
}
}