java架构师学习路线-Spring技术中常用的扩展点
Spring作为一个优秀的企业级应用框架,提供了企业开发过程中大多数基础功能的支持,如:事务,切面,web支持,数据库支持,ORM,OXM等等等等。但它不仅仅只是提供了这些基础功能,而是在提供这些基础功能的同时,给开发人员留下了许许多多的功能扩展点,使用者可以利用这些扩展点随意加入自己想要的其他功能,这也是Spring开闭原则的精髓。比如:常见的一些企业中间件例如:Dubbo,JSF,MyBatis,又或者是近些年比较流行的微服务框架SpringCloud等,其功能都是在Spring提供的扩展点之上扩展出来的新功能。那么Spring中经常使用到的扩展点有哪些呢?
扩展原理
Spring功能扩展的前提是它将对象的创建及容器的初始化等过程细分为了许多的步骤【这些步骤称为容器的声明周期和Bean的声明周期】,那么假设不这样做,直接使用new关键字创建出对象,顶多两步【先new对象,然后set属性】也就结束了,就不会有扩展这一说了。而在Spring中提供了一些很特别的接口,这些接口具有一个特点,他们会在容器初始化或者Bean实例化的过程中的某些时间点【例如:bean定义加载完毕,bean实例化前后,bean初始化前后】被调用,从而完成功能的扩展,在某个时间点可以插入自定义的处理逻辑,这也就是Spring的扩展原理。
原始扩展点
原始扩展点此处指的是原始的接口或者抽象类,没有其他的任何父接口或者父类。常见的此类扩展点有如下几个。
1、BeanFactoryPostProcessor
(1)扩展点方法
voidpostProcessBeanFactory(ConfigurableListableBeanFactorybeanFactory);
(2)扩展点的执行时机
该扩展点为一个beanFactory的后置处理器,它的执行时机是在Bean定义全部解析及加载完毕【加载完毕指的是bean定义已经被放入到了bean定义注册中心beanDefinitonMap中】,但是bean实例化之前会被执行。具体是在Spring容器初始化上下文,执行refresh方法的第5步执行的,即:
@Override
publicvoidrefresh(){
synchronized(this.startupShutdownMonitor){
try{
//…前4步略,后面文章介绍
//第5步:执行所有Bean工厂的后置处理器
//在该步骤中首先会去加载Bean定义,然后执行beanFactory的后置处理器
invokeBeanFactoryPostProcessors(beanFactory);
//…中间5步略,后面文章介绍
//第11步:完成所有单实例bean的创建及初始化
finishBeanFactoryInitialization(beanFactory);
//第12步:发布容器刷新事件,例如ContextRefreshedEvent
//SpringCloud的web服务也是在该步骤中启动的
finishRefresh();
}catch(BeansExceptionex){
}finally{
}
}
}
(3)该扩展点的作用
使用该扩展点,可以在实例化Bean实例之前修改Bean的定义信息。例如:修改bean的类型,修改bean的作用域,是否为懒加载,是否参与自动装配或者是修改bean的工厂方法等等【在Spring中Bean定义是专门用来描述bean的一种结构,里面包括了bean的方方面面的信息,在创建bean实例以及初始化bean的过程中就是根据bean定义中的信息来完成的】。
(4)扩展点使用示例
配置类ExtConfig
/**
*@authorwangbin33
@dateCreatedin12:162019/12/7
/
@Configuration
@ComponentScan(basePackages=“com.wb.spring.ext”)
publicclassExtConfig{
}
自定义bean工厂后置处理器
/
*@authorwangbin33
@dateCreatedin12:242019/12/7
/
@Component
publicclassMyBeanFactoryPostProcessorimplementsBeanFactoryPostProcessor{
@Override
publicvoidpostProcessBeanFactory(ConfigurableListableBeanFactorybeanFactory)throwsBeansException{
//获取已经加载的bean定义的数量
intcount=beanFactory.getBeanDefinitionCount();
//获取已经加载的bean定义的名称
String[]beanNames=beanFactory.getBeanDefinitionNames();
//根据bean定义的名称获取具体的bean定义
BeanDefinitionperBeanDefinition=beanFactory.getBeanDefinition(“person”);
//修改bean定义,bean定义中的许多属性此处都可以修改
//修改之后,创建bean实例的时候就会应用到修改之后的新属性值
perBeanDefinition.setAutowireCandidate(false);
System.out.println(perBeanDefinition);
}
}
测试类TestMain
/
*@authorwangbin33
@dateCreatedin12:162019/12/7
/
publicclassTestMain{
publicstaticvoidmain(String[]args){
AnnotationConfigApplicationContextacx=newAnnotationConfigApplicationContext();
acx.register(ExtConfig.class);
acx.refresh();
//容器关闭
acx.close();
}
}
这样从容器中获取到的person就是使用修改之后的bean定义创建的对象。
2、BeanPostProcessor
(1)扩展点的方法
publicinterfaceBeanPostProcessor{
/
*该方法是在Bean实例化(new)之后,初始化(设置各种属性)之前会被调用
在调用afterPropertiesSet方法之前会被调用
/
@Nullable
defaultObjectpostProcessBeforeInitialization(Objectbean,StringbeanName)throwsBeansException{
returnbean;
}
/
*在bean初始化之后会被调用
在调用InitializingBean的afterPropertiesSet方法或者init-method指定的方法执行之后调用.
/
@Nullable
defaultObjectpostProcessAfterInitialization(Objectbean,StringbeanName)throwsBeansException{
returnbean;
}
}
(2)扩展点的执行时机
该扩展点是和Bean相关的一个接口,主要是用来拦截Bean的创建,接口中包括两个扩展方法,postProcessBeforeXXX以及postProcessAfterXXX。
postProcessBeforeXXX执行时机:在Spring实例化bean并填充属性之后,执行初始化方法之前执行【初始化方法此处主要有两个:①使用init-method指定的方法;②Bean实例从InitializingBean接口中实现过来的afterPropertiesSet方法】。
postProcessAfterXXX执行时机:在Spring执行完初始化方法之后执行,如果当前Bean需要生成代理【AOP和声明式事务都会在该步骤中对目标bean对象生成代理对象】,则会在该步骤中生成。
(3)该扩展点的作用
由于该扩展点是在bean实例化完成,初始化方法执行前后调用的。所以可以利用该扩展点完成一些特定标识的检查,例如判断其是否实现了自定义的某个接口,然后对bean对象作出某种定制化操作。或者说对生成的对象进行包装,生成代理对象等等。
(4)使用示例
直接自定义Processor,然后实现BeanPostProcessor接口,然后实现其对应的后置处理方法即可。
/
*@authorwangbin33
@dateCreatedin12:162019/12/7
/
@Component
publicclassMyBeanPostProcessorimplementsBeanPostProcessor{
@Override
publicObjectpostProcessBeforeInitialization(Objectbean,StringbeanName)throwsBeansException{
if(beaninstanceofMyInterFace){
//检查其是否实现了某个自定义接口,然后做自定义操作
(MyInterFace(bean)).doSomeThing();
}
//返回原对象,或者包装为代理对象
returnbean;
}
@Override
publicObjectpostProcessAfterInitialization(Objectbean,StringbeanName)throwsBeansException{
returnnull;
}
}
3、ApplicationListener
Spring提供的用于事件驱动开发的一个扩展点,开发者可以给容器中发布自定义的事件,当事件发生之后,触发某个动作。
(1)扩展点的方法
@FunctionalInterface
publicinterfaceApplicationListenerextendsEventListener{
/
自定义事件实现该接口,在容器中发布事件之后,当时间发生时,触发onApplicationEvent的回调
/
voidonApplicationEvent(Eevent);
}
(2)扩展点的执行时机
容器发布默认的刷新事件时,自定义的事件会被触发执行。这个时候容器中的所有单实例bean都已经创建完成。
(3)扩展点的作用
在容器中的所有单实例bean都创建完成之后,可以做一些自定义的操作,例如启动某个后台线程。再比如在SpringCloud中,内嵌的web容器就是在容器发布事件的时候启动的,再有一些RPC服务框架,也可以再事件的回调方法中去发布或者注册服务接口。
(4)扩展点使用示例
①配置类ExtConfig
/
*@authorwangbin33
@dateCreatedin12:162019/12/7
/
@Configuration
@ComponentScan(basePackages=“com.wb.spring.ext”)
publicclassExtConfig{
}
②自定义事件实现
/
*@authorwangbin33
@dateCreatedin13:132019/12/7
/
@Component
publicclassMyApplicationListenerimplementsApplicationListener{
/
*当容器中发布事件之后,会触发该方法
@parameventtheeventtorespondto
/
@Override
publicvoidonApplicationEvent(ApplicationEventevent){
System.out.println(“收到事件:”+event);
}
}
③测试类
/
*@authorwangbin33
*@dateCreatedin12:162019/12/7
*/
publicclassTestMain{
publicstaticvoidmain(String[]args){
AnnotationConfigApplicationContextacx=newAnnotationConfigApplicationContext();
acx.register(ExtConfig.class);
acx.refresh();
acx.publishEvent(newApplicationEvent(newString(“wb发布的事件…”)){});
//发布一个自定义事件.
//容器关闭
acx.close();
}
}
在容器刷新过程中,首先会给容器中注册事件派发器,事件派发器其实就是用来执行事件回调的。然后调用publishEvent之后,底层会使用时间派发器去派发事件,即:执行事件的回调方法。
更多java高级培训****可前往:https://www.tulingxueyuan.cn/course/detail/493.html
更多Java高级培训免费学习地址:https://www.tulingxueyuan.cn/course.html
加群即可领取图灵学院最新Java高级架构师教程资料学习包 群号:116273821