成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

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

開發(fā) 前端
當(dāng) Spring 容器創(chuàng)建一個(gè) Bean 的時(shí)候,就會提前被 BeanPostProcessor 攔截,然后給出一個(gè) TargetSource,進(jìn)而據(jù)此創(chuàng)建代理對象,這樣就不需要后續(xù)常規(guī)的 Bean 創(chuàng)建流程了。

今天再來聊一個(gè) Spring 中的冷門知識:Bean 的處理不走正常流程,而是提前進(jìn)行 AOP。

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

在 Bean 創(chuàng)建的過程中,會先給 BeanPostProcessor 一個(gè)返回代理對象的機(jī)會:

@Override
protected 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è)返回代理對象的機(jī)會,在這個(gè)方法中,最終就會觸發(fā)到 InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation 方法,而在 postProcessBeforeInstantiation 方法中,會先判斷當(dāng)前 bean 是否是 AOP 相關(guān)類等:

@Override
public 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;
}

這里主要來說說 getCustomTargetSource 中的邏輯。

先來說什么情況下會走到 getCustomTargetSource 方法:當(dāng)前 Bean 不是代理對象,也不是 AOP 相關(guān)的類,就是一個(gè)普普通通的常規(guī)類,那么就會走到 getCustomTargetSource 方法這里來,這里失去查找到一個(gè) TargetSource 對象,然后根據(jù)該對象創(chuàng)建當(dāng)前 bean 的代理對象并返回,如果返回了代理對象,那么后續(xù)的 bean 創(chuàng)建流程就不執(zhí)行了。

我們來看下這個(gè)方法的源碼:

@Nullable
protected 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)前類 AbstractAutoProxyCreator 中有一個(gè) customTargetSourceCreators 變量,現(xiàn)在就是遍歷該變量,通過這個(gè)集合中保存的 TargetSourceCreator 來創(chuàng)建 TargetSource 對象。

TargetSourceCreator 是一個(gè)接口,這個(gè)接口只有一個(gè)抽象類 AbstractBeanFactoryBasedTargetSourceCreator,我們來看下 AbstractBeanFactoryBasedTargetSourceCreator 中的 getTargetSource 方法是怎么執(zhí)行的:

@Override
@Nullable
public 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 對象是通過 createBeanFactoryBasedTargetSource 方法來創(chuàng)建的,這個(gè)方法是一個(gè)抽象方法,將來在子類中被實(shí)現(xiàn)。

接下來會調(diào)用 getInternalBeanFactoryForBean 方法創(chuàng)建一個(gè)新的內(nèi)部容器 internalBeanFactory,本質(zhì)上這個(gè) internalBeanFactory 其實(shí)是一個(gè)子容器,現(xiàn)有的容器將作為這個(gè)子容器的父容器。

接下來就是獲取到當(dāng)前 beanName 所對應(yīng)的 BeanDefinition,然后進(jìn)行屬性配置,并注冊到內(nèi)部容器中,最后返回 targetSource 對象。

我們來看下這里的 getInternalBeanFactoryForBean 方法:

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)建,倒也沒啥好說的,但是有幾個(gè)需要注意的點(diǎn):

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

好了,這就是大致的 AOP 提前生成原理,接下來松哥寫一個(gè)案例我們一起來看下。

2. 實(shí)踐

首先,我們先來自定義一個(gè) TargetSource:

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)和大家介紹過很多了,這里我就不再啰嗦了。

接下來自定義 TargetSourceCreator:

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 的話,那么就給返回一個(gè) UserServiceTargetSource 對象。

最后,也是最關(guān)鍵的一步,根據(jù)前面的分析,TargetSourceCreator 是存在于 AnnotationAwareAspectJAutoProxyCreator 這樣一個(gè) InstantiationAwareBeanPostProcessor 類型的后置處理器中的,因此,我們要想辦法把自定義的 TargetSourceCreator 設(shè)置給 AnnotationAwareAspectJAutoProxyCreator,如下:

@Component
public 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 容器啟動時(shí)候的 refresh 方法中去初始化的。

BeanPostProcessor 初始化的時(shí)候,先初始化實(shí)現(xiàn)了 PriorityOrdered 接口的,再初始化實(shí)現(xiàn)了 Ordered 接口的,最后再去初始化那些沒有實(shí)現(xiàn)任何排序接口的 BeanPostProcessor。

而我們這里 SetCustomTargetSourceCreator 一定要趕在 AnnotationAwareAspectJAutoProxyCreator 之前進(jìn)行初始化,這樣,當(dāng) AnnotationAwareAspectJAutoProxyCreator 進(jìn)行初始化的時(shí)候,就會用到 SetCustomTargetSourceCreator 這樣一個(gè)后置處理器,進(jìn)而在該處理器中修改 AnnotationAwareAspectJAutoProxyCreator 的屬性。

AnnotationAwareAspectJAutoProxyCreator 類間接實(shí)現(xiàn)了 Ordered 接口,默認(rèn)優(yōu)先級是最低,但是在 Spring 容器啟動時(shí),在處理 BeanFactoryPostProcessor 時(shí)(具體是 ConfigurationClassPostProcessor),將其優(yōu)先級設(shè)置為最高。

所以,我們?nèi)绻胍屪远x的 SetCustomTargetSourceCreator 搶在 AnnotationAwareAspectJAutoProxyCreator 之前執(zhí)行,那么就只能讓 SetCustomTargetSourceCreator 去實(shí)現(xiàn) PriorityOrdered 接口了,實(shí)現(xiàn) PriorityOrdered 接口之后,重寫 getOrder 方法,這個(gè)方法返回值是什么無所謂,反正都會在實(shí)現(xiàn)了 Ordered 接口的 BeanPostProcessor 之前執(zhí)行。

最后,我們再在啟動類上開啟自動代理即可:

@Configuration
@ComponentScan
@EnableAspectJAutoProxy
public class JavaConfig {
}

大功告成。

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

責(zé)任編輯:武曉燕 來源: 江南一點(diǎn)雨
相關(guān)推薦

2020-09-06 22:59:35

Linux文件命令

2019-08-09 14:20:46

微信軟件手機(jī)

2020-11-16 11:24:00

Spring AOP數(shù)據(jù)庫

2024-09-26 14:48:35

SpringAOP范式

2020-08-17 08:20:16

iOSAOP框架

2023-12-27 08:24:05

射頻天線電波

2011-03-24 09:34:41

SPRING

2014-11-19 13:06:59

2009-06-18 14:54:52

Spring AOP

2021-04-07 15:55:35

微信朋友圈技巧

2014-08-18 14:58:25

微軟IE

2015-07-29 15:05:01

2022-10-21 14:27:53

元宇宙網(wǎng)絡(luò)空間稀缺虛擬環(huán)境

2021-08-26 11:02:55

云計(jì)算云計(jì)算環(huán)境云應(yīng)用

2020-11-13 07:08:51

Spring Boot應(yīng)用Spring

2013-01-15 14:32:03

移動社交商務(wù)社交藍(lán)海

2025-02-25 13:00:00

JavaScript開發(fā)前端

2013-01-17 10:09:50

JavaSpring

2019-12-17 18:25:35

物聯(lián)網(wǎng)電腦互聯(lián)網(wǎng)

2024-04-11 11:26:11

邊緣計(jì)算物聯(lián)網(wǎng)數(shù)據(jù)分析
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 一区二区三区四区免费视频 | 91精品久久久久久久久中文字幕 | 成人在线视频网 | 中国三级黄色录像 | 请别相信他免费喜剧电影在线观看 | 一区二区国产精品 | 91精品国产91久久综合桃花 | 日韩伦理一区二区 | 久久久久久九九九九九九 | www国产成人免费观看视频,深夜成人网 | 在线观看免费av网站 | 久久精品国产精品青草 | 1级毛片 | 免费观看的黄色网址 | 欧美精品网 | 国产精品成av人在线视午夜片 | 久青草影院 | h视频在线免费 | 久久久久亚洲精品中文字幕 | 亚洲一区二区不卡在线观看 | 国产日韩欧美在线播放 | 国产一区二区三区免费 | 国产精品毛片在线 | 免费国产黄 | 色欧美综合| 秋霞影院一区二区 | 国产福利91精品 | 免费成人高清在线视频 | 黄色三级免费网站 | 卡通动漫第一页 | 欧美不卡视频一区发布 | 中文字幕第一页在线 | 色爱综合网 | 中文字幕成人网 | 亚洲美女一区 | 欧美激情精品久久久久久 | 日本成人午夜影院 | 国产一区二区三区四区在线观看 | 午夜精品久久久久久久久久久久久 | 一级全黄视频 | 久久伊人在 |