AVt天堂网 手机版,亚洲va久久久噜噜噜久久4399,天天综合亚洲色在线精品,亚洲一级Av无码毛片久久精品

當(dāng)前位置:首頁(yè) > 科技  > 軟件

Spring 冷知識(shí):一個(gè)提前 AOP 的機(jī)會(huì)

來(lái)源: 責(zé)編: 時(shí)間:2023-10-30 09:06:44 296觀看
導(dǎo)讀今天再來(lái)聊一個(gè) Spring 中的冷門(mén)知識(shí):Bean 的處理不走正常流程,而是提前進(jìn)行 AOP。1. Bean 創(chuàng)建流程在 Bean 創(chuàng)建的過(guò)程中,會(huì)先給 BeanPostProcessor 一個(gè)返回代理對(duì)象的機(jī)會(huì):@Overrideprotected Object createBean(Strin

今天再來(lái)聊一個(gè) Spring 中的冷門(mén)知識(shí):Bean 的處理不走正常流程,而是提前進(jìn)行 AOP。BYL28資訊網(wǎng)——每日最新資訊28at.com

1. Bean 創(chuàng)建流程

在 Bean 創(chuàng)建的過(guò)程中,會(huì)先給 BeanPostProcessor 一個(gè)返回代理對(duì)象的機(jī)會(huì):BYL28資訊網(wǎng)——每日最新資訊28at.com

@Overrideprotected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)  throws BeanCreationException { //省略。。。 try {  // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.  Object bean = resolveBeforeInstantiation(beanName, mbdToUse);  if (bean != null) {   return bean;  } } catch (Throwable ex) {  throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,    "BeanPostProcessor before instantiation of bean failed", ex); } try {  Object beanInstance = doCreateBean(beanName, mbdToUse, args);  if (logger.isTraceEnabled()) {   logger.trace("Finished creating instance of bean '" + beanName + "'");  }  return beanInstance; }    //省略。。。}

小伙伴們看,這里的 resolveBeforeInstantiation 方法就是給 BeanPostProcessor 一個(gè)返回代理對(duì)象的機(jī)會(huì),在這個(gè)方法中,最終就會(huì)觸發(fā)到 InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation 方法,而在 postProcessBeforeInstantiation 方法中,會(huì)先判斷當(dāng)前 bean 是否是 AOP 相關(guān)類(lèi)等:BYL28資訊網(wǎng)——每日最新資訊28at.com

@Overridepublic Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) { Object cacheKey = getCacheKey(beanClass, beanName); if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {  if (this.advisedBeans.containsKey(cacheKey)) {   return null;  }  if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {   this.advisedBeans.put(cacheKey, Boolean.FALSE);   return null;  } }  TargetSource targetSource = getCustomTargetSource(beanClass, beanName); if (targetSource != null) {  if (StringUtils.hasLength(beanName)) {   this.targetSourcedBeans.add(beanName);  }  Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);  Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);  this.proxyTypes.put(cacheKey, proxy.getClass());  return proxy; } return null;}

這里主要來(lái)說(shuō)說(shuō) getCustomTargetSource 中的邏輯。BYL28資訊網(wǎng)——每日最新資訊28at.com

先來(lái)說(shuō)什么情況下會(huì)走到 getCustomTargetSource 方法:當(dāng)前 Bean 不是代理對(duì)象,也不是 AOP 相關(guān)的類(lèi),就是一個(gè)普普通通的常規(guī)類(lèi),那么就會(huì)走到 getCustomTargetSource 方法這里來(lái),這里失去查找到一個(gè) TargetSource 對(duì)象,然后根據(jù)該對(duì)象創(chuàng)建當(dāng)前 bean 的代理對(duì)象并返回,如果返回了代理對(duì)象,那么后續(xù)的 bean 創(chuàng)建流程就不執(zhí)行了。BYL28資訊網(wǎng)——每日最新資訊28at.com

我們來(lái)看下這個(gè)方法的源碼:BYL28資訊網(wǎng)——每日最新資訊28at.com

@Nullableprotected TargetSource getCustomTargetSource(Class<?> beanClass, String beanName) { // We can't create fancy target sources for directly registered singletons. if (this.customTargetSourceCreators != null &&   this.beanFactory != null && this.beanFactory.containsBean(beanName)) {  for (TargetSourceCreator tsc : this.customTargetSourceCreators) {   TargetSource ts = tsc.getTargetSource(beanClass, beanName);   if (ts != null) {    return ts;   }  } } // No custom TargetSource found. return null;}

可以看到,這里就是當(dāng)前類(lèi) AbstractAutoProxyCreator 中有一個(gè) customTargetSourceCreators 變量,現(xiàn)在就是遍歷該變量,通過(guò)這個(gè)集合中保存的 TargetSourceCreator 來(lái)創(chuàng)建 TargetSource 對(duì)象。BYL28資訊網(wǎng)——每日最新資訊28at.com

TargetSourceCreator 是一個(gè)接口,這個(gè)接口只有一個(gè)抽象類(lèi) AbstractBeanFactoryBasedTargetSourceCreator,我們來(lái)看下 AbstractBeanFactoryBasedTargetSourceCreator 中的 getTargetSource 方法是怎么執(zhí)行的:BYL28資訊網(wǎng)——每日最新資訊28at.com

@Override@Nullablepublic final TargetSource getTargetSource(Class<?> beanClass, String beanName) { AbstractBeanFactoryBasedTargetSource targetSource =   createBeanFactoryBasedTargetSource(beanClass, beanName); if (targetSource == null) {  return null; } DefaultListableBeanFactory internalBeanFactory = getInternalBeanFactoryForBean(beanName); // We need to override just this bean definition, as it may reference other beans // and we're happy to take the parent's definition for those. // Always use prototype scope if demanded. BeanDefinition bd = getConfigurableBeanFactory().getMergedBeanDefinition(beanName); GenericBeanDefinition bdCopy = new GenericBeanDefinition(bd); if (isPrototypeBased()) {  bdCopy.setScope(BeanDefinition.SCOPE_PROTOTYPE); } internalBeanFactory.registerBeanDefinition(beanName, bdCopy); // Complete configuring the PrototypeTargetSource. targetSource.setTargetBeanName(beanName); targetSource.setBeanFactory(internalBeanFactory); return targetSource;}

首先,TargetSource 對(duì)象是通過(guò) createBeanFactoryBasedTargetSource 方法來(lái)創(chuàng)建的,這個(gè)方法是一個(gè)抽象方法,將來(lái)在子類(lèi)中被實(shí)現(xiàn)。BYL28資訊網(wǎng)——每日最新資訊28at.com

接下來(lái)會(huì)調(diào)用 getInternalBeanFactoryForBean 方法創(chuàng)建一個(gè)新的內(nèi)部容器 internalBeanFactory,本質(zhì)上這個(gè) internalBeanFactory 其實(shí)是一個(gè)子容器,現(xiàn)有的容器將作為這個(gè)子容器的父容器。BYL28資訊網(wǎng)——每日最新資訊28at.com

接下來(lái)就是獲取到當(dāng)前 beanName 所對(duì)應(yīng)的 BeanDefinition,然后進(jìn)行屬性配置,并注冊(cè)到內(nèi)部容器中,最后返回 targetSource 對(duì)象。BYL28資訊網(wǎng)——每日最新資訊28at.com

我們來(lái)看下這里的 getInternalBeanFactoryForBean 方法:BYL28資訊網(wǎng)——每日最新資訊28at.com

protected DefaultListableBeanFactory getInternalBeanFactoryForBean(String beanName) { synchronized (this.internalBeanFactories) {  return this.internalBeanFactories.computeIfAbsent(beanName,    name -> buildInternalBeanFactory(getConfigurableBeanFactory())); }}protected DefaultListableBeanFactory buildInternalBeanFactory(ConfigurableBeanFactory containingFactory) { // Set parent so that references (up container hierarchies) are correctly resolved. DefaultListableBeanFactory internalBeanFactory = new DefaultListableBeanFactory(containingFactory); // Required so that all BeanPostProcessors, Scopes, etc become available. internalBeanFactory.copyConfigurationFrom(containingFactory); // Filter out BeanPostProcessors that are part of the AOP infrastructure, // since those are only meant to apply to beans defined in the original factory. internalBeanFactory.getBeanPostProcessors().removeIf(beanPostProcessor ->   beanPostProcessor instanceof AopInfrastructureBean); return internalBeanFactory;}

這個(gè)其實(shí)就是正常的容器創(chuàng)建,倒也沒(méi)啥好說(shuō)的,但是有幾個(gè)需要注意的點(diǎn):BYL28資訊網(wǎng)——每日最新資訊28at.com

  1. 在調(diào)用 buildInternalBeanFactory 方法構(gòu)建容器的時(shí)候,會(huì)先調(diào)用 getConfigurableBeanFactory 方法獲取到當(dāng)前容器作為父容器,如果當(dāng)前容器不存在,那么就會(huì)拋出異常。這就意味著,當(dāng)我們自己提供 TargetSourceCreator 實(shí)例的時(shí)候,一定要指定一個(gè)容器。
  2. 在創(chuàng)建了內(nèi)部容器之后,會(huì)從內(nèi)部容器中移除所有 AopInfrastructureBean 類(lèi)型的 BeanPostProcessor,也就是內(nèi)部容器將來(lái)創(chuàng)建出來(lái)的 bean,不再走 AopInfrastructureBean 類(lèi)型后置處理器,因?yàn)檫@種類(lèi)型的后置處理器主要是用來(lái)處理 AOP 的,現(xiàn)在,AOP 代理當(dāng)場(chǎng)就生成了,就不再需要這些后置處理器了。

好了,這就是大致的 AOP 提前生成原理,接下來(lái)松哥寫(xiě)一個(gè)案例我們一起來(lái)看下。BYL28資訊網(wǎng)——每日最新資訊28at.com

2. 實(shí)踐

首先,我們先來(lái)自定義一個(gè) TargetSource:BYL28資訊網(wǎng)——每日最新資訊28at.com

public class UserServiceTargetSource extends AbstractBeanFactoryBasedTargetSource {    @Override    public Object getTarget() throws Exception {        return getBeanFactory().getBean(getTargetBeanName());    }    @Override    public boolean isStatic() {        return true;    }}

關(guān)于 TargetSource 本身,松哥在之前的 Spring 源碼視頻中已經(jīng)和大家介紹過(guò)很多了,這里我就不再啰嗦了。BYL28資訊網(wǎng)——每日最新資訊28at.com

接下來(lái)自定義 TargetSourceCreator:BYL28資訊網(wǎng)——每日最新資訊28at.com

public class CustomTargetSourceCreator extends AbstractBeanFactoryBasedTargetSourceCreator {    @Override    protected AbstractBeanFactoryBasedTargetSource createBeanFactoryBasedTargetSource(Class<?> beanClass, String beanName) {        if (getBeanFactory() instanceof ConfigurableListableBeanFactory) {            if (beanClass.isAssignableFrom(UserService.class)) {                return new UserServiceTargetSource();            }        }        return null;    }}

如果要?jiǎng)?chuàng)建的 bean 是 UserService 的話(huà),那么就給返回一個(gè) UserServiceTargetSource 對(duì)象。BYL28資訊網(wǎng)——每日最新資訊28at.com

最后,也是最關(guān)鍵的一步,根據(jù)前面的分析,TargetSourceCreator 是存在于 AnnotationAwareAspectJAutoProxyCreator 這樣一個(gè) InstantiationAwareBeanPostProcessor 類(lèi)型的后置處理器中的,因此,我們要想辦法把自定義的 TargetSourceCreator 設(shè)置給 AnnotationAwareAspectJAutoProxyCreator,如下:BYL28資訊網(wǎng)——每日最新資訊28at.com

@Componentpublic class SetCustomTargetSourceCreator implements BeanPostProcessor, PriorityOrdered, BeanFactoryAware {    private BeanFactory beanFactory;    @Override    public int getOrder() {        return Integer.MIN_VALUE;    }    @Override    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {        if(bean instanceof AnnotationAwareAspectJAutoProxyCreator) {            AnnotationAwareAspectJAutoProxyCreator annotationAwareAspectJAutoProxyCreator = (AnnotationAwareAspectJAutoProxyCreator)bean;            CustomTargetSourceCreator customTargetSourceCreator = new CustomTargetSourceCreator();            customTargetSourceCreator.setBeanFactory(beanFactory);            annotationAwareAspectJAutoProxyCreator.setCustomTargetSourceCreators(customTargetSourceCreator);        }        return bean;    }    @Override    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {        this.beanFactory = beanFactory;    }}

AnnotationAwareAspectJAutoProxyCreator 本身就是一個(gè) BeanPostProcessor,我們現(xiàn)在要做的就是修改這個(gè) BeanPostProcessor,BeanPostProcessor 是在 Spring 容器啟動(dòng)時(shí)候的 refresh 方法中去初始化的。BYL28資訊網(wǎng)——每日最新資訊28at.com

BeanPostProcessor 初始化的時(shí)候,先初始化實(shí)現(xiàn)了 PriorityOrdered 接口的,再初始化實(shí)現(xiàn)了 Ordered 接口的,最后再去初始化那些沒(méi)有實(shí)現(xiàn)任何排序接口的 BeanPostProcessor。BYL28資訊網(wǎng)——每日最新資訊28at.com

而我們這里 SetCustomTargetSourceCreator 一定要趕在 AnnotationAwareAspectJAutoProxyCreator 之前進(jìn)行初始化,這樣,當(dāng) AnnotationAwareAspectJAutoProxyCreator 進(jìn)行初始化的時(shí)候,就會(huì)用到 SetCustomTargetSourceCreator 這樣一個(gè)后置處理器,進(jìn)而在該處理器中修改 AnnotationAwareAspectJAutoProxyCreator 的屬性。BYL28資訊網(wǎng)——每日最新資訊28at.com

AnnotationAwareAspectJAutoProxyCreator 類(lèi)間接實(shí)現(xiàn)了 Ordered 接口,默認(rèn)優(yōu)先級(jí)是最低,但是在 Spring 容器啟動(dòng)時(shí),在處理 BeanFactoryPostProcessor 時(shí)(具體是 ConfigurationClassPostProcessor),將其優(yōu)先級(jí)設(shè)置為最高。BYL28資訊網(wǎng)——每日最新資訊28at.com

所以,我們?nèi)绻胍屪远x的 SetCustomTargetSourceCreator 搶在 AnnotationAwareAspectJAutoProxyCreator 之前執(zhí)行,那么就只能讓 SetCustomTargetSourceCreator 去實(shí)現(xiàn) PriorityOrdered 接口了,實(shí)現(xiàn) PriorityOrdered 接口之后,重寫(xiě) getOrder 方法,這個(gè)方法返回值是什么無(wú)所謂,反正都會(huì)在實(shí)現(xiàn)了 Ordered 接口的 BeanPostProcessor 之前執(zhí)行。BYL28資訊網(wǎng)——每日最新資訊28at.com

最后,我們?cè)僭趩?dòng)類(lèi)上開(kāi)啟自動(dòng)代理即可:BYL28資訊網(wǎng)——每日最新資訊28at.com

@Configuration@ComponentScan@EnableAspectJAutoProxypublic class JavaConfig {}

大功告成。BYL28資訊網(wǎng)——每日最新資訊28at.com

這樣,當(dāng) Spring 容器創(chuàng)建一個(gè) Bean 的時(shí)候,就會(huì)提前被 BeanPostProcessor 攔截,然后給出一個(gè) TargetSource,進(jìn)而據(jù)此創(chuàng)建代理對(duì)象,這樣就不需要后續(xù)常規(guī)的 Bean 創(chuàng)建流程了。好啦,感興趣的小伙伴可以自己去試一試哦~BYL28資訊網(wǎng)——每日最新資訊28at.com

本文鏈接:http://www.tebozhan.com/showinfo-26-15721-0.htmlSpring 冷知識(shí):一個(gè)提前 AOP 的機(jī)會(huì)

聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com

上一篇: 作為前端開(kāi)發(fā)者,你沒(méi)有必要學(xué) Rust

下一篇: 作為前端開(kāi)發(fā)者,你沒(méi)有必要學(xué) Rust

標(biāo)簽:
  • 熱門(mén)焦點(diǎn)
Top