Spring奇技淫巧之?dāng)U展點(diǎn)的應(yīng)用
?最近在看公司項(xiàng)目和中間件的時(shí)候,看到一些Spring擴(kuò)展點(diǎn)的使用,寫篇文章學(xué)習(xí)下,對(duì)大家之后看源碼都有幫助
?
「首先先介紹下Bean的生命周期」
我們知道Bean的生命周期分為幾個(gè)主干流程
-
Bean(單例非懶加載)的實(shí)例化階段 -
Bean的屬性注入階段 -
Bean的初始化階段 -
Bean的銷毀階段
下面是整個(gè)Spring容器的啟動(dòng)流程,可以看到除了上述幾個(gè)主干流程外,Spring還提供了很多擴(kuò)展點(diǎn)
下面詳細(xì)介紹下Spring的常見的擴(kuò)展點(diǎn)
Spring常見擴(kuò)展點(diǎn)
「BeanFactoryPostProcessor#postProcessBeanFactory」
有時(shí)候整個(gè)項(xiàng)目工程中bean的數(shù)量有上百個(gè),而大部分單測(cè)依賴都是整個(gè)工程的xml,導(dǎo)致單測(cè)執(zhí)行時(shí)需要很長時(shí)間(大部分時(shí)間耗費(fèi)在xml中數(shù)百個(gè)單例非懶加載的bean的實(shí)例化及初始化過程)
解決方法:利用Spring提供的擴(kuò)展點(diǎn)將xml中的bean設(shè)置為懶加載模式,省去了Bean的實(shí)例化與初始化時(shí)間
public class LazyBeanFactoryProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
DefaultListableBeanFactory fac = (DefaultListableBeanFactory) beanFactory;
Map<String, AbstractBeanDefinition> map = (Map<String, AbstractBeanDefinition>) ReflectionTestUtils.getField(fac, "beanDefinitionMap");
for (Map.Entry<String, AbstractBeanDefinition> entry : map.entrySet()) {
//設(shè)置為懶加載
entry.getValue().setLazyInit(true);
}
}
}
「InstantiationAwareBeanPostProcessor#postProcessPropertyValues」
非常規(guī)的配置項(xiàng)比如
<context:component-scan base-package="com.zhou" />
Spring提供了與之對(duì)應(yīng)的特殊解析器
正是通過這些特殊的解析器才使得對(duì)應(yīng)的配置項(xiàng)能夠生效
而針對(duì)這個(gè)特殊配置的解析器為 ComponentScanBeanDefinitionParser
在這個(gè)解析器的解析方法中,注冊(cè)了很多特殊的Bean
public BeanDefinition parse(Element element, ParserContext parserContext) {
//...
registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
//...
return null;
}
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, Object source) {
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<BeanDefinitionHolder>(4);
//...
//@Autowire
if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
//@Resource
if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
//特殊的Bean
RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
}
//...
return beanDefs;
}
以@Resource為例,看看這個(gè)特殊的bean做了什么
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor
implements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds,
Object bean, String beanName) throws BeansException {
InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass());
try {
//屬性注入
metadata.inject(bean, beanName, pvs);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
}
return pvs;
}
}
我們看到在postProcessPropertyValues方法中,進(jìn)行了屬性注入
「invokeAware」
實(shí)現(xiàn)BeanFactoryAware接口的類,會(huì)由容器執(zhí)行setBeanFactory方法將當(dāng)前的容器BeanFactory注入到類中
@Bean
class BeanFactoryHolder implements BeanFactoryAware{
private static BeanFactory beanFactory;
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
}
「BeanPostProcessor#postProcessBeforeInitialization」
實(shí)現(xiàn)ApplicationContextAware接口的類,會(huì)由容器執(zhí)行setApplicationContext方法將當(dāng)前的容器applicationContext注入到類中
@Bean
class ApplicationContextAwareProcessor implements BeanPostProcessor {
private final ConfigurableApplicationContext applicationContext;
public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Override
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
//...
invokeAwareInterfaces(bean);
return bean;
}
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}
}
我們看到是在BeanPostProcessor的postProcessBeforeInitialization中進(jìn)行了setApplicationContext方法的調(diào)用
class ApplicationContextHolder implements ApplicationContextAware{
private static ApplicationContext applicationContext;
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
「afterPropertySet()和init-method」
目前很多Java中間件都是基本Spring Framework搭建的,而這些中間件經(jīng)常把入口放到afterPropertySet或者自定義的init中
「BeanPostProcessor#postProcessAfterInitialization」
熟悉aop的同學(xué)應(yīng)該知道,aop底層是通過動(dòng)態(tài)代理實(shí)現(xiàn)的
當(dāng)配置了<aop:aspectj-autoproxy/>時(shí)候,默認(rèn)開啟aop功能,相應(yīng)地調(diào)用方需要被aop織入的對(duì)象也需要替換為動(dòng)態(tài)代理對(duì)象
不知道大家有沒有思考過動(dòng)態(tài)代理是如何「在調(diào)用方無感知情況下替換原始對(duì)象」的?
?根據(jù)上文的講解,我們知道:
?
<aop:aspectj-autoproxy/>
Spring也提供了特殊的解析器,和其他的解析器類似,在核心的parse方法中注冊(cè)了特殊的bean
這里是一個(gè)BeanPostProcessor類型的bean
class AspectJAutoProxyBeanDefinitionParser implements BeanDefinitionParser {
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
//注冊(cè)特殊的bean
AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
extendBeanDefinition(element, parserContext);
return null;
}
}
將于當(dāng)前bean對(duì)應(yīng)的動(dòng)態(tài)代理對(duì)象返回即可,該過程對(duì)調(diào)用方全部透明
public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.containsKey(cacheKey)) {
//如果該類需要被代理,返回動(dòng)態(tài)代理對(duì)象;反之,返回原對(duì)象
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
}
正是利用Spring的這個(gè)擴(kuò)展點(diǎn)實(shí)現(xiàn)了動(dòng)態(tài)代理對(duì)象的替換
「destroy()和destroy-method」
bean生命周期的最后一個(gè)擴(kuò)展點(diǎn),該方法用于執(zhí)行一些bean銷毀前的準(zhǔn)備工作,比如將當(dāng)前bean持有的一些資源釋放掉
最后
「寫文章畫圖不易,喜歡的話,希望幫忙點(diǎn)贊,轉(zhuǎn)發(fā)下哈,謝謝」
微信搜索:月伴飛魚,交個(gè)朋友
公眾號(hào)后臺(tái)回復(fù)666,獲得免費(fèi)電子書籍,必讀經(jīng)典書籍這里全都有
參考書籍:
-
Spring技術(shù)內(nèi)幕
-
Spring源碼深度解析
社招一年半面經(jīng)分享(含阿里美團(tuán)頭條京東滴滴)
條件語句的多層嵌套問題優(yōu)化,助你寫出不讓同事吐槽的代碼
