Spring提供了兩種後處理bean的擴充套件介面 --- 小結

Spring提供了兩種後處理bean的擴充套件介面,分別為BeanPostProcessor和BeanFactoryPostProcessor,這兩者在使用上是有所區別的。

Spring提供了兩種後處理bean的擴充套件介面 --- 小結

BeanPostProcessor:

bean級別的處理,針對某個具體的bean進行處理

public interface BeanPostProcessor { Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException; Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;}

介面提供了兩個方法,分別是初始化前和初始化後執行方法,具體這個初始化方法指的是什麼方法,類似我們在定義bean時,定義了init-method所指定的方法

init()

”>

這兩個方法分別在init方法前後執行,

需要注意一點,我們定義一個類實現了BeanPostProcessor,預設是會對整個Spring容器中所有的bean進行處理。

預設全部處理,那怎麼處理的某個具體的bean呢?

方法中有兩個引數。型別分別為Object和String,第一個引數是每個bean的例項,第二個引數是每個bean的name或者id屬性的值。所以我們可以第二個引數,來確認我們將要處理的具體的bean。這個的處理是發生在Spring容器的例項化和依賴注入之後。

BeanFactoryPostProcessor:

BeanFactory級別的處理,是針對整個Bean的工廠進行處理

當我們呼叫BeanFactoryPostProcess方法時,這時候bean還沒有例項化,此時bean剛被解析成BeanDefinition物件。

Spring容器初始化bean大致過程 :

1。定義bean標籤>2。將bean標籤解析成BeanDefinition>3。呼叫構造方法例項化(IOC)>4。屬性值得依賴注入(DI)

BeanFactoryPostProcess方法的執行是發生在 2 之後,3 之前。

在application context執行完標準初始化之後,所有bean definition都已載入,但還沒有例項化任何bean。BeanFactoryPostProcessor允許插手修改context內部bean工廠,允許覆蓋或新增屬性。

@Componentpublic class XDemoBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { BeanDefinition beanDefinition =beanFactory。getBeanDefinition(“userDemoDao”); beanDefinition。setScope(“prototype”); }}

BeanDefinitionRegistryPostProcessor

BeanFactoryPostProcessor介面有一個重要的子介面BeanDefinitionRegistryPostProcessor

當我們用Spring來管理應用,我們會讓Spring來管理所有的Bean。

除了註解、Java配置和XML配置的方式來建立Bean,還有另外一種方式來建立我們的

BeanDefinition

透過

BeanDefinitionRegistryPostProcessor

可以建立一個特別後置處理器來將

BeanDefinition

新增到

BeanDefinitionRegistry

中。

public class XDemoBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor { @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { System。out。println(“XDemoBeanDefinitionRegistryPostProcessor。。。postProcessBeanDefinitionRegistry”); System。out。println(registry。getBeanDefinitionCount()); //RootBeanDefinition beanDefinition = new RootBeanDefinition(Pig。class); 作用同下行 AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder。rootBeanDefinition(Pig。class)。getBeanDefinition(); registry。registerBeanDefinition(“pig”,beanDefinition); } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { System。out。println(“ XDemoBeanDefinitionRegistryPostProcessor。。。postProcessBeanFactory”); System。out。println(beanFactory。getBeanDefinitionCount()); }}

@Configuration@Import({XDemoBeanFactoryPostProcessor。class,XDemoBeanDefinitionRegistryPostProcessor。class})public class TestConfig { @Bean public Pig pigCreate(){ return new Pig(); }}

BeanFactoryPostProcessor

不同,

BeanPostProcessor

只是在Bean初始化的時候有個鉤子讓我們加入一些自定義操作。

BeanDefinitionRegistryPostProcessor

可以讓我們在

BeanDefinition

中新增一些自定義操作,對我們自己的

BeanDefinition

進行註冊。

在Mybatis與Spring的整合中,就利用到了BeanDefinitionRegistryPostProcessor來對Mapper的BeanDefinition進行了後置的自定義處理。

在Spring的配置檔案中,我們會配置以下程式碼來掃描Mapper:

<!—— 指定掃描的包,如果存在多個包使用(逗號,)分割 ——>

MapperScannerConfigurer類的主要工作,總結起來就是掃描basePackage包下所有的mapper介面類,並將mapper介面類封裝成為BeanDefinition物件,註冊到spring的BeanFactory容器中:

Spring提供了兩種後處理bean的擴充套件介面 --- 小結

首先根據這個mapper的名字從spring的BeanFactory中獲取它的BeanDefinition,再從BeanDefinition中獲取BeanClass,xxxMapper對應的BeanClass就是MapperFactoryBean

MapperFactoryBean物件的屬性設定完成之後,就呼叫它的getObject()方法,來獲取authUserMapper對應的實現類,從上面圖中可以看出來,最後返回的就是一個代理類,這個代理類使用jdk的動態代理創建出來的。

@Servicepublic class DemoServiceImpl implements DemoUserService { @Resource private XxxMapper xxxUserMapper; }

return Proxy。newProxyInstance(this。mapperInterface。getClassLoader(), new Class[]{this。mapperInterface}, mapperProxy);

public class MapperProxy implements InvocationHandler, Serializable { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (Object。class。equals(method。getDeclaringClass())) { return method。invoke(this, args); } else { MapperMethod mapperMethod = this。cachedMapperMethod(method); return mapperMethod。execute(this。sqlSession, args); } }}

程式在呼叫xxxMapper物件的某個方法的時候,就會呼叫到MapperProxy物件的invoke()方法,去完成對資料庫的操作。