BeanPostProcessor和BeanFactoryPostProcessor是Spring中兩個最重要的擴展的。如果說BeanFactoryPostProcessor是面向IoC進行擴展,BeanPostProcessor就是面向Bean進行擴展。
從上面類結(jié)構(gòu)圖可以看出,BeanPostProcessor是一個頂層接口,下面有衍生出幾個接口,實現(xiàn)對Bean創(chuàng)建、初始化等各個階段進行更細化的擴展,所以BeanPostProcessor要比BeanFactoryPostProcessor復(fù)雜一些,可以實現(xiàn)更多擴展場景。
(相關(guān)資料圖)
BeanPostProcessor被注冊到IoC中才能起作用,在refresh()方法中registerBeanPostProcessors(beanFactory);這一語句完成BeanPostProcessor的注冊工作,注冊使用:addBeanPostProcessor(BeanPostProcessor beanPostProcessor)方法完成。
注冊BeanPostProcessor也涉及到先后順序關(guān)系,大致邏輯總結(jié)如下:
1、獲取實現(xiàn)PriorityOrdered接口的BeanPostProcessor,然后通過getBean()方法實例化,排序后注冊到容器中;2、獲取實現(xiàn)Ordered接口的BeanPostProcessor,然后通過getBean()方法實例化,排序后注冊到容器中;3、獲取常規(guī)沒有實現(xiàn)PriorityOrdered和Ordered接口BeanPostProcessor,然后通過getBean()方法實例化,注冊到容器中;4、上述步驟中MergedBeanDefinitionPostProcessor類型會單獨存儲到internalPostProcessors集合中,排序后保證放到末尾5、最后移除ApplicationListenerDetector重新追加到最末尾上面只是BeanPostProcessor注冊先后順序關(guān)系,并不會涉及到BeanPostProcessor的執(zhí)行,由于BeanPostProcessor擴展出幾個子類,下面我們來分析下每個子類的執(zhí)行時機。
接口定義見下:
public interface BeanPostProcessor { @Nullable default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; } @Nullable default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; }}之前分析IoC容器啟動流程時,介紹過initializeBean()方法完成Bean的init-method初始化工作,BeanPostProcessor就是在init-method執(zhí)行前后進行擴展。
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) { Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { //觸發(fā)BeanPostProcessor#postProcessBeforeInitialization()方法執(zhí)行 wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } //執(zhí)行init-method方法 invokeInitMethods(beanName, wrappedBean, mbd); if (mbd == null || !mbd.isSynthetic()) { //觸發(fā)BeanPostProcessor#postProcessAfterInitialization()方法執(zhí)行 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean;}再來看下這兩個方法的調(diào)用邏輯:
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; for (BeanPostProcessor processor : getBeanPostProcessors()) { Object current = processor.postProcessBeforeInitialization(result, beanName); if (current == null) { return result; } result = current; } return result;}如果有postProcessBeforeInitialization()方法返回null,則表示該擴展點提前結(jié)束,不再需要繼續(xù)執(zhí)行后續(xù)BeanPostProcessor的postProcessBeforeInitialization方法。
再來看下postProcessAfterInitialization()方法執(zhí)行邏輯是一樣的:
@Override public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; for (BeanPostProcessor processor : getBeanPostProcessors()) { Object current = processor.postProcessAfterInitialization(result, beanName); if (current == null) { return result; } result = current; } return result; }invokeInitMethods(beanName, wrappedBean, mbd);方法執(zhí)行Bean的init-method方法進行初始化,進入這個方法可以發(fā)現(xiàn),這里只會執(zhí)行實現(xiàn)InitializingBean和@Bean(initMethod="xxx")這兩種方式設(shè)置的init-method方法,我們平時使用很多的@PostConstruct注解方式,其實是通過InitDestroyAnnotationBeanPostProcessor這個擴展類實現(xiàn):
InitDestroyAnnotationBeanPostProcessor類實現(xiàn)了DestructionAwareBeanPostProcessor和MergedBeanDefinitionPostProcessor這兩個接口,間接方式繼承BeanPostProcessor。InitDestroyAnnotationBeanPostProcessor就是在postProcessBeforeInitialization()方法中完成了對@PostConstruct注解方法的調(diào)用,所以其執(zhí)行優(yōu)先級比InitializingBean和@Bean(initMethod="xxx")這兩種方式更加靠前。
如果你需要在init-method等Bean的初始化執(zhí)行前后進行擴展,可以使用此接口實現(xiàn)。比如:判斷Bean是否是線程池類,如果是則統(tǒng)一設(shè)置管理的線程名前綴:
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof ThreadPoolTaskExecutor) { ((ThreadPoolTaskExecutor) bean).setThreadNamePrefix("Post-"); } return bean;}還比如ApplicationListenerDetector在postProcessAfterInitialization()方法中實現(xiàn)將ApplicationListener類型的單例Bean注冊到事件多播器上,實現(xiàn)對事件的監(jiān)聽:
public Object postProcessAfterInitialization(Object bean, String beanName) { if (bean instanceof ApplicationListener) { Boolean flag = this.singletonNames.get(beanName); if (Boolean.TRUE.equals(flag)) { // 如果當(dāng)前 ApplicationListener bean scope 是 singleton 單例模式,則將它注冊到應(yīng)用的事件多播器上 this.applicationContext.addApplicationListener((ApplicationListener>) bean); } else if (Boolean.FALSE.equals(flag)) { // 如果ApplicationListener bean scope 不是 singleton 單例模式,則嘗試輸出警告日志,說明情況,并移除 //所以ApplicationListener類型的只能是單例模式才會起作用 this.singletonNames.remove(beanName); } } return bean;}還比如ApplicationContextAwareProcessor這個就是在postProcessBeforeInitialization()方法中實現(xiàn)如ApplicationContextAware、EnvironmentAware等*Aware接口注入功能。實現(xiàn)原理非常簡單,就是判斷Bean是否實現(xiàn)接口,然后通過setter方式注入即可:
private void invokeAwareInterfaces(Object bean) { if (bean instanceof EnvironmentAware) { ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment()); } if (bean instanceof EmbeddedValueResolverAware) { ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver); } if (bean instanceof ResourceLoaderAware) { ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext); } if (bean instanceof ApplicationEventPublisherAware) { ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext); } if (bean instanceof MessageSourceAware) { ((MessageSourceAware) bean).setMessageSource(this.applicationContext); } if (bean instanceof ApplicationContextAware) { ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext); }}前面分析BeanPostProcessor接口是在Bean的init-method方法執(zhí)行前后進行擴展,其子接口InstantiationAwareBeanPostProcessor則可以在Bean的創(chuàng)建前后進行擴展,所以此擴展比BeanPostProcessor擴展更靠前。
接口定義見下:
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor { //Bean創(chuàng)建之前回調(diào)該方法,beanClass就是將要被創(chuàng)建的Bean對應(yīng)的Class信息 @Nullable default Object postProcessBeforeInstantiation(Class> beanClass, String beanName) throws BeansException { return null; } //Bean創(chuàng)建之后回調(diào)該方法,參數(shù)bean就是創(chuàng)建完成的Bean對象 default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException { return true; } //postProcessProperties()方法在postProcessAfterInstantiation()方法之后緊挨著執(zhí)行,其提供PropertyValues類型入?yún)ⅲ栽谠摲椒ㄖ锌梢詫崿F(xiàn)依賴操作 @Nullable default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException { return null; } //這個方法標注@Deprecated已經(jīng)被廢棄了,被postProcessProperties()方法取代了 @Deprecated @Nullable default PropertyValues postProcessPropertyValues( PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException { return pvs; }}createBean()方法中Object bean = resolveBeforeInstantiation(beanName, mbdToUse);這條語句中會觸發(fā)對postProcessBeforeInstantiation()方法的執(zhí)行。
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { Object bean = resolveBeforeInstantiation(beanName, mbdToUse);//觸發(fā)對postProcessBeforeInstantiation()方法的執(zhí)行 if (bean != null) { return bean; } ... Object beanInstance = doCreateBean(beanName, mbdToUse, args);//創(chuàng)建Bean實例(一般真正創(chuàng)建Bean的方法) ...}InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation()方法有個重要特性:如果該方法返回非null結(jié)果,則表示Bean提前創(chuàng)建完成,同時也會忽略掉后續(xù)的依賴注入、init-method初始化等步驟執(zhí)行,最后只需要執(zhí)行下BeanPostProcessor#postProcessAfterInitialization這個方法則整個Bean的創(chuàng)建流程就全部完成。
總結(jié):在創(chuàng)建對象之前調(diào)用了postProcessBeforeInstantiation方法可以實現(xiàn)給擴展點一次創(chuàng)建代理的機會,如果代理對象返回不為空則不再繼續(xù)常規(guī)方式創(chuàng)建Bean。
我們再來看下InstantiationAwareBeanPostProcessor接口中定義的另兩個方法執(zhí)行時機,Bean創(chuàng)建完成后會執(zhí)行populateBean()進行依賴注入,它們就是在這個方法中進行觸發(fā)回調(diào),pupulateBean()方法大致見下:
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) { //執(zhí)行InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation方法回調(diào) if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { return; } } } } // 注解注入:后置處理器ibp#postProcessProperties,大名鼎鼎的@Autowired就是在這處理的。 PropertyDescriptor[] filteredPds = null; if (hasInstAwareBpps) { //執(zhí)行InstantiationAwareBeanPostProcessor#postProcessProperties方法回調(diào) for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName); if (pvsToUse == null) { if (filteredPds == null) { //獲取出對象的所有set get方法,現(xiàn)在是有一個 getClass()方法,因為繼承了Object, 沒什么其他卵用 filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); } //postProcessPropertyValues方法已廢棄,被postProcessProperties替代 pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); if (pvsToUse == null) { return; } } pvs = pvsToUse; } } } if (pvs != null) { applyPropertyValues(beanName, mbd, bw, pvs); }}上面代碼翻譯下大概就是:先執(zhí)行InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation方法回調(diào),然后再去執(zhí)行InstantiationAwareBeanPostProcessor#postProcessProperties,最后再去執(zhí)行applyPropertyValues()完成PropertyValue方式的依賴注入。這里有個大名鼎鼎的@Autowired、@Value方式的依賴注入,就是借助于InstantiationAwareBeanPostProcessor#postProcessProperties()方法實現(xiàn),這個實現(xiàn)類就是:AutowiredAnnotationBeanPostProcessor,簡單看下依賴注入邏輯:
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) { /** * 從緩存中找到此類的@Autowired、@Value注解元數(shù)據(jù),嘗試注入 * InjectionMetadata,持有待注入的元數(shù)據(jù)信息,執(zhí)行inject()方法,開始注入屬性或方法參數(shù)。 */ InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs); try { //為beanName填充上屬性bean metadata.inject(bean, beanName, pvs); } catch (BeanCreationException ex) { throw ex; } catch (Throwable ex) { throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex); } return pvs;}這里有意義的代碼就兩行:
1、InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);獲取Bean中需要依賴注入注入的元素,封裝成一個InjectionMetadata對象,該對象有兩個重要屬性:
targetClass指定目標對象的Class;Collection injectedElements :目標對象中每個需要依賴注入的元素都會封裝成一個InjectedElement,然后存儲到該集合中。根據(jù)@Autowired/@Value注解到字段上還是方法上,InjectedElement又可以分為兩類:AutowiredFieldElement和AutowiredMethodElement。2、metadata.inject(bean, beanName, pvs);:這個方法內(nèi)部就是循環(huán),對每個依賴元素InjectedElement調(diào)用inject()方法
if (!elementsToIterate.isEmpty()) { for (InjectedElement element : elementsToIterate) { if (logger.isTraceEnabled()) { logger.trace("Processing injected element of bean "" + beanName + "": " + element); } element.inject(target, beanName, pvs); }}比如我們一般將@Autowired標注到字段上,則這里會觸發(fā)AutowiredFieldElement#inject()方法執(zhí)行:
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable { Field field = (Field) this.member;//依賴注入字段 Object value;//存儲需要注入的值 if (this.cached) {//如果已被緩存,則直接先從緩存中獲取依賴注入值 value = resolvedCachedArgument(beanName, this.cachedFieldValue); } else {//還未被緩存過 //1.DependencyDescriptor:用于對該依賴注入描述信息 DependencyDescriptor desc = new DependencyDescriptor(field, this.required); desc.setContainingClass(bean.getClass()); Set autowiredBeanNames = new LinkedHashSet<>(1); Assert.state(beanFactory != null, "No BeanFactory available"); TypeConverter typeConverter = beanFactory.getTypeConverter(); try { /* 2.查找依賴注入的值 比如: @Autowired private TestService03 testService03; 這個value就是從IoC容器中查找到的TestService03對象 還比如:@Value("${spring.name}"),這個value就是從Spring上下文環(huán)境變量中解析出的spring.name變量值 */ value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter); } catch (BeansException ex) { throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex); } //3.下面synchronized塊主要實現(xiàn)緩存功能,已被解析過的包裝成ShortcutDependencyDescriptor類型,上面resolvedCachedArgument對這種類型會特殊處理 synchronized (this) { if (!this.cached) { if (value != null || this.required) { this.cachedFieldValue = desc; registerDependentBeans(beanName, autowiredBeanNames); if (autowiredBeanNames.size() == 1) { String autowiredBeanName = autowiredBeanNames.iterator().next(); if (beanFactory.containsBean(autowiredBeanName) && beanFactory.isTypeMatch(autowiredBeanName, field.getType())) { this.cachedFieldValue = new ShortcutDependencyDescriptor( desc, autowiredBeanName, field.getType()); } } } else { this.cachedFieldValue = null; } this.cached = true; } } } //4.查找到的依賴值不為null,則使用反射方式注入,因為是通過反射方式,所以@Autowired、@Value是不需要setter/getter方法也可以注入 if (value != null) { //通過反射方式將查找到的需要依賴注入的值設(shè)置到對象實例中 ReflectionUtils.makeAccessible(field); field.set(bean, value); }} InstantiationAwareBeanPostProcessor還有個子接口:SmartInstantiationAwareBeanPostProcessor,其定義如下:
public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor { //推斷類型 @Nullable default Class> predictBeanType(Class> beanClass, String beanName) throws BeansException { return null; } //根據(jù)一定規(guī)則推斷出Bean中優(yōu)選的構(gòu)造方法 @Nullable default Constructor>[] determineCandidateConstructors(Class> beanClass, String beanName) throws BeansException { return null; } default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException { return bean; }}SmartInstantiationAwareBeanPostProcessor接口有三個方法,在實例創(chuàng)建前智能判斷實例類型、智能判斷構(gòu)造函數(shù)、提起獲取暴露Bean引用,該接口主要是spring框架內(nèi)部使用,開發(fā)時很少去擴展該接口。
這里主要注意第三個方法:getEarlyBeanReference(),這個擴展方法主要與Spring中的循環(huán)依賴有關(guān)系。前面分析IoC容器啟動時分析過:為了解決Spring中的循環(huán)依賴問題,在doCreateBean()方法內(nèi)部,會將剛創(chuàng)建還未來得及進行依賴注入和初始化的半成品Bean提前暴露出去,addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));,注意這里不是直接將Bean暴露出去,而是通過() -> getEarlyBeanReference(beanName, mbd, bean)這句將Bean包裝成ObjectFactory類型再暴露出去。
這里的一個核心就是:為什么不直接暴露Bean,而是將Bean包裝成ObjectFactory再去暴露?將Bean包裝成ObjectFactory再去暴露,調(diào)用getObject()方法時會觸發(fā)SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference方法回調(diào)。
分析到這里,還不夠完善,因為你可能會問:那這個方法回調(diào)又可以給我們解決什么問題呢?
可以利用Spring AOP原理來回答這個問題,Spring AOP主要基于AnnotationAwareAspectJAutoProxyCreator這個類實現(xiàn),這個類實現(xiàn)了BeanPostProcessor接口,在postProcessAfterInitialization()方法中對創(chuàng)建完成的Bean采用動態(tài)代理方式將增強邏輯織入進去。
如果存在這樣情況:A依賴B,B同時依賴A,這就是所說的Spring循環(huán)依賴,但是如果我們對A采用了AOP增強,這個過程會是怎樣情況呢?
init-method初始化方法后,postProcessAfterInitialization()執(zhí)行時會給A通過動態(tài)代理方式織入增強邏輯;這時,步驟3中給B注入的是A的原生對象,但是步驟6會給A創(chuàng)建一個代理對象,但是B中這時還是原生對象沒法改變,這就會導(dǎo)致有的依賴注入的是原生對象,有的依賴注入的是代理對象,會出現(xiàn)錯亂問題。如何解決呢?這個就是SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference這個擴展點作用。
A對象提前暴露時,利用ObjectFactory包裝了一層,B對象在進行依賴注入時獲取到對象A時,不是直接返回A,而是觸發(fā)getEarlyBeanReference()方法執(zhí)行,AnnotationAwareAspectJAutoProxyCreator類在getEarlyBeanReference()方法中實現(xiàn)判斷A需要做動態(tài)代理,則對A進行動態(tài)代理后返回,這時B中依賴注入的就不是原生對象。
總結(jié):SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference()方法是在循環(huán)依賴場景下,對提前暴露的Bean可以通過該擴展點進行處理。只有因為存在循環(huán)依賴,才會導(dǎo)致需要需要獲取那些提前暴露的Bean時才會觸發(fā)該擴展點,所以,理解這個擴展點關(guān)鍵在于你對Spring循環(huán)依賴的理解。
DestructionAwareBeanPostProcessor是BeanPostProcessor子接口,其定義如下:
public interface DestructionAwareBeanPostProcessor extends BeanPostProcessor { //Bean銷毀前回調(diào)方法 void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException; //可以根據(jù)Bean進行過濾,哪些Bean需要用到當(dāng)前這個回調(diào) default boolean requiresDestruction(Object bean) { return true; }}從名稱就可以看出,該擴展主要用于Bean銷毀之前,回調(diào)時機在:DisposableBeanAdapter#destroy()
public void destroy() { //調(diào)用DestructionAwareBeanPostProcessor#postProcessBeforeDestruction,Bean銷毀之前回調(diào)接口 if (!CollectionUtils.isEmpty(this.beanPostProcessors)) { for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) { processor.postProcessBeforeDestruction(this.bean, this.beanName); } } ... ((DisposableBean) this.bean).destroy();//調(diào)用DisposableBean.destroy() ... }DestructionAwareBeanPostProcessor接口有個實現(xiàn)類InitDestroyAnnotationBeanPostProcessor,實現(xiàn)對@PreDestroy注解支持。該擴展接口本身是比較簡單的,后續(xù)分析Bean生命周期destroy流程整體梳理。
MergedBeanDefinitionPostProcessor
public interface MergedBeanDefinitionPostProcessor extends BeanPostProcessor { void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class> beanType, String beanName); //Spring5.1新增接口,實現(xiàn)BeanDefinition重置通知,一般該方法實現(xiàn)重置前清理metadata等元數(shù)據(jù)緩存 default void resetBeanDefinition(String beanName) { }}我們主要看下postProcessMergedBeanDefinition()方法調(diào)用時機:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException { //1.創(chuàng)建對象 //2.執(zhí)行MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition回調(diào)方法 synchronized (mbd.postProcessingLock) { if (!mbd.postProcessed) { applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); mbd.postProcessed = true; } } //3.提前暴露Bean //4.populateBean(beanName, mbd, instanceWrapper); //5.exposedObject = initializeBean(beanName, exposedObject, mbd);}MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition發(fā)生在Bean剛創(chuàng)建完成,Bean還未提前暴露之前。MergedBeanDefinitionPostProcessor在Spring中有很多的應(yīng)用,比如:AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、InitDestroyAnnotationBeanPostProcessor等。這個擴展的一般套路是和其它擴展點一起使用,其起到一個幫手角色,postProcessMergedBeanDefinition將需要處理的注解信息解析成元數(shù)據(jù)信息緩存起來,其它擴展點就可以從緩存中獲取需要處理的注解信息進行處理。有關(guān)這擴展點更多的情況會在后續(xù)案例分析中再詳細分析。
BeanFactoryPostProcessor和BeanPostProcessor是Spring提供的兩個最核心、最基礎(chǔ)的擴展方式:一個面向IoC進行擴展,另一個面向Bean的創(chuàng)建流程進行各種擴展。BeanPostProcessor及其子類實現(xiàn)了對Bean創(chuàng)建過程中的各種擴展:Bean創(chuàng)建前后、Bean初始化前后、獲取提前暴露對象前等等這些。Spring中大量注解簡化了我們使用框架的復(fù)雜性,而這些注解很大一部分就是基于這些擴展進行處理,學(xué)習(xí)這些擴展點可以幫助我們更好的熟悉Spring的運行機理,同時可以在開發(fā)中幫助我們靈活的實現(xiàn)各種功能擴展。
關(guān)鍵詞: