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

Spring AOP 中的代理對象是怎么創建出來的?

開發 前端
首先實例化就是通過反射,先把 Bean 的實例創建出來;接下來屬性賦值就是給創建出來的 Bean 的各個屬性賦值;接下來的初始化就是給 Bean 應用上各種需要的后置處理器;最后則是銷毀。

1. AOP 用法

先來一個簡單的案例,小伙伴們先回顧一下 AOP,假設我有如下類:

@Service
public class UserService {

    public void hello() {
        System.out.println("hello javaboy");
    }
}

然后我寫一個切面,攔截 UserService 中的方法:

@Component
@Aspect
@EnableAspectJAutoProxy
public class LogAspect {

    @Before("execution(* org.javaboy.bean.aop.UserService.*(..))")
    public void before(JoinPoint jp) {
        String name = jp.getSignature().getName();
        System.out.println(name+" 方法開始執行了...");
    }
}

最后,我們看一下從 Spring 容器中獲取到的 UserService 對象:

ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("aop.xml");
UserService us = ctx.getBean(UserService.class);
System.out.println("us.getClass() = " + us.getClass());

打印結果如下:

圖片圖片

可以看到,獲取到的 UserService 是一個代理對象。

其他各種類型的通知我這里就不說了,不熟悉的小伙伴可以在公眾號【江南一點雨】后臺回復 ssm,有松哥錄制的免費入門視頻。

2. 原理分析

那么注入到 Spring 容器中的 UserService,為什么在獲取的時候變成了一個代理對象,而不是原本的 UserService 了呢?

整體上來說,我們可以將 Spring Bean 的生命周期分為四個階段,分別是:

實例化。

屬性賦值。

初始化。

銷毀。

如下圖:

圖片圖片

首先實例化就是通過反射,先把 Bean 的實例創建出來;接下來屬性賦值就是給創建出來的 Bean 的各個屬性賦值;接下來的初始化就是給 Bean 應用上各種需要的后置處理器;最后則是銷毀。

2.1 doCreateBean

AOP 代理對象的創建是在初始化這個過程中完成的,所以今天我們就從初始化這里開始看起。

AbstractAutowireCapableBeanFactory#doCreateBean:

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
  throws BeanCreationException {
    //...
 try {
  populateBean(beanName, mbd, instanceWrapper);
  exposedObject = initializeBean(beanName, exposedObject, mbd);
 }
 //...
 return exposedObject;
}

小伙伴們看到,這里有一個 initializeBean 方法,在這個方法中會對 Bean 執行各種后置處理器:

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
 invokeAwareMethods(beanName, bean);
 Object wrappedBean = bean;
 if (mbd == null || !mbd.isSynthetic()) {
  wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
 }
 try {
  invokeInitMethods(beanName, wrappedBean, mbd);
 }
 catch (Throwable ex) {
  throw new BeanCreationException(
    (mbd != null ? mbd.getResourceDescription() : null), beanName, ex.getMessage(), ex);
 }
 if (mbd == null || !mbd.isSynthetic()) {
  wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
 }
 return wrappedBean;
}

這里一共是執行了四個方法,也都是非常常見的 Bean 初始化方法:

  1. invokeAwareMethods:執行 Aware 接口下的 Bean。
  2. applyBeanPostProcessorsBeforeInitialization:執行 BeanPostProcessor 中的前置方法。
  3. invokeInitMethods:執行 Bean 的初始化方法 init。
  4. applyBeanPostProcessorsAfterInitialization:執行 BeanPostProcessor 中的后置方法。

1、3 這兩個方法很明顯跟 AOP 關系不大,我們自己平時創建的 AOP 對象基本上都是在 applyBeanPostProcessorsAfterInitialization 中進行處理的,我們來看下這個方法:

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

小伙伴們看到,這里就是遍歷各種 BeanPostProcessor,并執行其 postProcessAfterInitialization 方法,將執行結果賦值給 result 并返回。

2.2 postProcessAfterInitialization

BeanPostProcessor 有一個實現類 AbstractAutoProxyCreator,在 AbstractAutoProxyCreator 的 postProcessAfterInitialization 方法中,進行了 AOP 的處理:

@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
 if (bean != null) {
  Object cacheKey = getCacheKey(bean.getClass(), beanName);
  if (this.earlyProxyReferences.remove(cacheKey) != bean) {
   return wrapIfNecessary(bean, beanName, cacheKey);
  }
 }
 return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
 if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
  return bean;
 }
 if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
  return bean;
 }
 if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
  this.advisedBeans.put(cacheKey, Boolean.FALSE);
  return bean;
 }
 // Create proxy if we have advice.
 Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
 if (specificInterceptors != DO_NOT_PROXY) {
  this.advisedBeans.put(cacheKey, Boolean.TRUE);
  Object proxy = createProxy(
    bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
  this.proxyTypes.put(cacheKey, proxy.getClass());
  return proxy;
 }
 this.advisedBeans.put(cacheKey, Boolean.FALSE);
 return bean;
}

可以看到,首先會嘗試去緩存中獲取代理對象,如果緩存中沒有的話,則會調用 wrapIfNecessary 方法進行 AOP 的創建。

正常來說,普通 AOP 的創建,前面三個 if 的條件都是不滿足的。第一個 if 是說 beanName 是否是一個 targetSource,顯然我們這里不是;第二個 if 是說這個 Bean 是不是不需代理(結合上篇文章一起理解),我們這里顯然是需要代理的;第三個 if 的作用我們也在上篇文章中和小伙伴們介紹過,這里就不再贅述了。

關于第二個 if 我多說一句,如果這里進來的是一個切面的 Bean,例如第一小節中的 LogAspect,這種 Bean 顯然是不需要代理的,所以會在第二個方法中直接返回,如果是其他普通的 Bean,則第二個 if 并不會進來。

所在在 wrapIfNecessary 中,最重要的方法實際上就是兩個:getAdvicesAndAdvisorsForBean 和 createProxy,前者用來找出來所有跟當前類匹配的切面,后者則用來創建代理對象。

2.3 getAdvicesAndAdvisorsForBean

這個方法,說白了,就是查找各種 Advice(通知/增強) 和 Advisor(切面)。來看下到底怎么找的:

AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean:

@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(
  Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
 List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
 if (advisors.isEmpty()) {
  return DO_NOT_PROXY;
 }
 return advisors.toArray();
}

從這里可看到,這個方法主要就是調用 findEligibleAdvisors 去獲取到所有的切面,繼續:

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
 List<Advisor> candidateAdvisors = findCandidateAdvisors();
 List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
 extendAdvisors(eligibleAdvisors);
 if (!eligibleAdvisors.isEmpty()) {
  eligibleAdvisors = sortAdvisors(eligibleAdvisors);
 }
 return eligibleAdvisors;
}

這里一共有三個主要方法:

  • findCandidateAdvisors:這個方法是查詢到所有候選的 Advisor,說白了,就是把項目啟動時注冊到 Spring 容器中所有切面都找到,由于一個 Aspect 中可能存在多個 Advice,每個 Advice 最終都能封裝為一個 Advisor,所以在具體查找過程中,找到 Aspect Bean 之后,還需要遍歷 Bean 中的方法。
  • findAdvisorsThatCanApply:這個方法主要是從上個方法找到的所有切面中,根據切點過濾出來能夠應用到當前 Bean 的切面。
  • extendAdvisors:這個是添加一個 DefaultPointcutAdvisor 切面進來,這個切面使用的 Advice 是 ExposeInvocationInterceptor,ExposeInvocationInterceptor 的作用是用于暴露  MethodInvocation 對象到 ThreadLocal 中,如果其他地方需要使用當前的 MethodInvocation 對象,直接通過調用 currentInvocation 方法取出即可。

接下來我們就來看一下這三個方法的具體實現。

2.3.1 findCandidateAdvisors

AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors

@Override
protected List<Advisor> findCandidateAdvisors() {
 List<Advisor> advisors = super.findCandidateAdvisors();
 if (this.aspectJAdvisorsBuilder != null) {
  advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
 }
 return advisors;
}

這個方法的關鍵在于通過 buildAspectJAdvisors 構建出所有的切面,這個方法有點復雜:

public List<Advisor> buildAspectJAdvisors() {
 List<String> aspectNames = this.aspectBeanNames;
 if (aspectNames == null) {
  synchronized (this) {
   aspectNames = this.aspectBeanNames;
   if (aspectNames == null) {
    List<Advisor> advisors = new ArrayList<>();
    aspectNames = new ArrayList<>();
    String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
      this.beanFactory, Object.class, true, false);
    for (String beanName : beanNames) {
     if (!isEligibleBean(beanName)) {
      continue;
     }
     // We must be careful not to instantiate beans eagerly as in this case they
     // would be cached by the Spring container but would not have been weaved.
     Class<?> beanType = this.beanFactory.getType(beanName, false);
     if (beanType == null) {
      continue;
     }
     if (this.advisorFactory.isAspect(beanType)) {
      aspectNames.add(beanName);
      AspectMetadata amd = new AspectMetadata(beanType, beanName);
      if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
       MetadataAwareAspectInstanceFactory factory =
         new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
       List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
       if (this.beanFactory.isSingleton(beanName)) {
        this.advisorsCache.put(beanName, classAdvisors);
       }
       else {
        this.aspectFactoryCache.put(beanName, factory);
       }
       advisors.addAll(classAdvisors);
      }
      else {
       // Per target or per this.
       if (this.beanFactory.isSingleton(beanName)) {
        throw new IllegalArgumentException("Bean with name '" + beanName +
          "' is a singleton, but aspect instantiation model is not singleton");
       }
       MetadataAwareAspectInstanceFactory factory =
         new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
       this.aspectFactoryCache.put(beanName, factory);
       advisors.addAll(this.advisorFactory.getAdvisors(factory));
      }
     }
    }
    this.aspectBeanNames = aspectNames;
    return advisors;
   }
  }
 }
 if (aspectNames.isEmpty()) {
  return Collections.emptyList();
 }
 List<Advisor> advisors = new ArrayList<>();
 for (String aspectName : aspectNames) {
  List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
  if (cachedAdvisors != null) {
   advisors.addAll(cachedAdvisors);
  }
  else {
   MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
   advisors.addAll(this.advisorFactory.getAdvisors(factory));
  }
 }
 return advisors;
}

這個方法第一次進來的時候,aspectNames 變量是沒有值的,所以會先進入到 if 分支中,給 aspectNames 和 aspectBeanNames 兩個變量賦值。

具體過程就是首先調用 BeanFactoryUtils.beanNamesForTypeIncludingAncestors 方法(不熟悉該方法的小伙伴參考 Spring 中的父子容器是咋回事?一文),去當前容器以及當前容器的父容器中,查找到所有的 beanName,將返回的數組賦值給 beanNames 變量,然后對 beanNames 進行遍歷。

遍歷時,首先調用 isEligibleBean 方法,這個方法是檢查給定名稱的 Bean 是否符合自動代理的條件的,這個細節我們就不看了,因為一般情況下,我們項目中的 AOP 都是自動代理的。

接下來根據 beanName,找到對應的 bean 類型 beanType,然后調用 advisorFactory.isAspect 方法去判斷這個 beanType 是否是一個 Aspect,具體的判斷過程上篇文章講過了,小伙伴們可以參考。

如果當前 beanName 對應的 Bean 是一個 Aspect,那么就把 beanName 添加到 aspectNames 集合中,并且把 beanName 和 beanType 封裝為一個 AspectMetadata 對象。

接下來會去判斷 kind 是否為 SINGLETON,這個默認都是 SINGLETON,所以這里會進入到分支中,進來之后,會調用 this.advisorFactory.getAdvisors 方法去 Aspect 中找到各種通知和切點并封裝成 Advisor 對象返回,由于一個切面中可能定義多個通知,所以最終返回的 Advisor 是一個集合,最后把找到的 Advisor 集合存入到 advisorsCache 緩存中。

后面方法的邏輯就很好懂了,從 advisorsCache 中找到某一個 aspect 對應的所有 Advisor,并將之存入到 advisors 集合中,然后返回集合。

這樣,我們就找到了所有的 Advisor。

2.3.2 findAdvisorsThatCanApply

接下來 findAdvisorsThatCanApply 方法主要是從眾多的 Advisor 中,找到能匹配上當前 Bean 的 Advisor,小伙伴們知道,每一個 Advisor 都包含一個切點 Pointcut,不同的切點意味著不同的攔截規則,所以現在需要進行匹配,檢查當前類需要和哪個 Advisor 匹配:

protected List<Advisor> findAdvisorsThatCanApply(
  List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
 ProxyCreationContext.setCurrentProxiedBeanName(beanName);
 try {
  return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
 }
 finally {
  ProxyCreationContext.setCurrentProxiedBeanName(null);
 }
}

這里實際上就是調用了靜態方法 AopUtils.findAdvisorsThatCanApply 去查找匹配的 Advisor:

public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
 if (candidateAdvisors.isEmpty()) {
  return candidateAdvisors;
 }
 List<Advisor> eligibleAdvisors = new ArrayList<>();
 for (Advisor candidate : candidateAdvisors) {
  if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
   eligibleAdvisors.add(candidate);
  }
 }
 boolean hasIntroductions = !eligibleAdvisors.isEmpty();
 for (Advisor candidate : candidateAdvisors) {
  if (candidate instanceof IntroductionAdvisor) {
   // already processed
   continue;
  }
  if (canApply(candidate, clazz, hasIntroductions)) {
   eligibleAdvisors.add(candidate);
  }
 }
 return eligibleAdvisors;
}

這個方法中首先會去判斷 Advisor 的類型是否是 IntroductionAdvisor 類型,IntroductionAdvisor 類型的 Advisor 只能在類級別進行攔截,靈活度不如 PointcutAdvisor,所以我們一般都不是 IntroductionAdvisor,因此這里最終會走入到最后一個分支中:

public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
 if (advisor instanceof IntroductionAdvisor ia) {
  return ia.getClassFilter().matches(targetClass);
 }
 else if (advisor instanceof PointcutAdvisor pca) {
  return canApply(pca.getPointcut(), targetClass, hasIntroductions);
 }
 else {
  // It doesn't have a pointcut so we assume it applies.
  return true;
 }
}

從這里小伙伴們就能看到,IntroductionAdvisor 類型的 Advisor 只需要調用 ClassFilter 過濾一下就行了,ClassFilter 松哥在前面的文章中已經介紹過了(玩一玩編程式 AOP),小伙伴們看這里的匹配邏輯也是非常 easy!而 PointcutAdvisor 類型的 Advisor 則會繼續調用 canApply 方法進行判斷:

public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
 if (!pc.getClassFilter().matches(targetClass)) {
  return false;
 }
 MethodMatcher methodMatcher = pc.getMethodMatcher();
 if (methodMatcher == MethodMatcher.TRUE) {
  // No need to iterate the methods if we're matching any method anyway...
  return true;
 }
 IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
 if (methodMatcher instanceof IntroductionAwareMethodMatcher iamm) {
  introductionAwareMethodMatcher = iamm;
 }
 Set<Class<?>> classes = new LinkedHashSet<>();
 if (!Proxy.isProxyClass(targetClass)) {
  classes.add(ClassUtils.getUserClass(targetClass));
 }
 classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
 for (Class<?> clazz : classes) {
  Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
  for (Method method : methods) {
   if (introductionAwareMethodMatcher != null ?
     introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
     methodMatcher.matches(method, targetClass)) {
    return true;
   }
  }
 }
 return false;
}

小伙伴們看一下,這里就是先按照類去匹配,匹配通過則繼續按照方法去匹配,方法匹配器要是設置的 true,那就直接返回 true 就行了,否則就加載當前類,也就是 targetClass,然后遍歷 targetClass 中的所有方法,最后調用 introductionAwareMethodMatcher.matches 方法去判斷方法是否和切點契合。

就這樣,我們就從所有的 Advisor 中找到了所有和當前類匹配的 Advisor 了。

2.3.3 extendAdvisors

這個是添加一個 DefaultPointcutAdvisor 切面進來,這個切面使用的 Advice 是 ExposeInvocationInterceptor,ExposeInvocationInterceptor 的作用是用于暴露 MethodInvocation 對象到 ThreadLocal 中,如果其他地方需要使用當前的 MethodInvocation 對象,直接通過調用 currentInvocation 方法取出即可。

這個方法的邏輯比較簡單,我就不貼出來了,小伙伴們可以自行查看。

2.4 createProxy

看完了 getAdvicesAndAdvisorsForBean 方法,我們已經找到了適合我們的 Advisor,接下來繼續看 createProxy 方法,這個方法用來創建一個代理對象:

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
  @Nullable Object[] specificInterceptors, TargetSource targetSource) {
 return buildProxy(beanClass, beanName, specificInterceptors, targetSource, false);
}
private Object buildProxy(Class<?> beanClass, @Nullable String beanName,
  @Nullable Object[] specificInterceptors, TargetSource targetSource, boolean classOnly) {
 if (this.beanFactory instanceof ConfigurableListableBeanFactory clbf) {
  AutoProxyUtils.exposeTargetClass(clbf, beanName, beanClass);
 }
 ProxyFactory proxyFactory = new ProxyFactory();
 proxyFactory.copyFrom(this);
 if (proxyFactory.isProxyTargetClass()) {
  // Explicit handling of JDK proxy targets and lambdas (for introduction advice scenarios)
  if (Proxy.isProxyClass(beanClass) || ClassUtils.isLambdaClass(beanClass)) {
   // Must allow for introductions; can't just set interfaces to the proxy's interfaces only.
   for (Class<?> ifc : beanClass.getInterfaces()) {
    proxyFactory.addInterface(ifc);
   }
  }
 }
 else {
  // No proxyTargetClass flag enforced, let's apply our default checks...
  if (shouldProxyTargetClass(beanClass, beanName)) {
   proxyFactory.setProxyTargetClass(true);
  }
  else {
   evaluateProxyInterfaces(beanClass, proxyFactory);
  }
 }
 Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
 proxyFactory.addAdvisors(advisors);
 proxyFactory.setTargetSource(targetSource);
 customizeProxyFactory(proxyFactory);
 proxyFactory.setFrozen(this.freezeProxy);
 if (advisorsPreFiltered()) {
  proxyFactory.setPreFiltered(true);
 }
 // Use original ClassLoader if bean class not locally loaded in overriding class loader
 ClassLoader classLoader = getProxyClassLoader();
 if (classLoader instanceof SmartClassLoader smartClassLoader && classLoader != beanClass.getClassLoader()) {
  classLoader = smartClassLoader.getOriginalClassLoader();
 }
 return (classOnly ? proxyFactory.getProxyClass(classLoader) : proxyFactory.getProxy(classLoader));
}

這段代碼不知道小伙伴們看了是否覺得眼熟,這就是前面發的另類 AOP,編程式 AOP!一文中的內容,所以這塊源碼大家自己看看就好了,我就不啰嗦了。


責任編輯:武曉燕 來源: 江南一點雨
相關推薦

2022-09-29 09:17:47

進程Linux創建

2023-02-27 08:09:42

SpringAOP代理

2023-10-08 10:14:12

2022-09-01 10:40:29

SpringAOPJDK

2024-04-01 08:38:57

Spring@AspectAOP

2019-11-29 16:21:22

Spring框架集成

2012-07-11 14:31:16

SpringAop

2022-06-24 09:36:47

Python對象調用

2021-05-14 00:00:15

JavaScript開發代碼

2025-01-16 08:45:48

2021-07-27 22:56:00

JavaScript編程開發

2021-07-01 10:45:18

Bean對象作用域

2023-03-29 08:24:30

2020-06-22 08:50:27

Spring AOP代理

2024-11-04 16:29:19

2024-03-04 07:41:18

SpringAOPOOP?

2021-10-27 07:15:37

SpringAOP編程(

2010-04-26 08:53:06

面向方面編程.NET

2024-11-28 11:59:57

2009-06-16 15:02:18

面向對象編程PHP異常PHP代理
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 香蕉久久av| 国产精品视频一区二区三区四蜜臂 | 欧洲精品在线观看 | 99久久精品免费看国产四区 | 欧洲亚洲视频 | 一级片在线视频 | 国产精品成人免费 | 在线成人免费视频 | 久久久久91| 精品国产一区二区三区久久久久久 | 国产精品久久网 | 亚洲成人一区 | 中文字幕视频在线看5 | 欧美日韩国产精品一区二区 | 中文一区二区 | 成人免费福利视频 | h视频免费观看 | 亚洲一区视频在线 | 欧美久久一区 | 久久久91精品国产一区二区三区 | 韩国欧洲一级毛片 | 亚洲成人网在线播放 | 伊人超碰 | 免费看大片bbbb欧美 | 成人3d动漫一区二区三区91 | 国产一级特黄真人毛片 | 国产中文字幕网 | 欧美日韩不卡合集视频 | 久久中文字幕电影 | 精品中文在线 | 伊人伊成久久人综合网站 | 欧美男人天堂 | 一级毛片视频在线观看 | 久久另类视频 | 国产在线a | 久久精品一区二区 | 男人的天堂中文字幕 | 日韩美女一区二区三区在线观看 | 亚洲高清成人 | 99re在线| 亚洲精品www|