<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      spring詳解-AOP

      Spring分析-AOP

      1.案例引入

      在上一篇文章中,【Spring--IOC】【 http://www.rzrgm.cn/jackjavacpp/p/18829545
      ,我們了解到了IOC容器的創建過程,在文末也提到了AOP相關,但是沒有作細致分析,這篇文章就結合示例,來詳細分析一下Spring-AOP。

      本文章示例代碼見該倉庫:【spring】中的“spring”模塊。

      倉庫地址:https://gitee.com/quercus-sp204/sourcecode-and-demos

      本節AOP示例代碼如下:[ 在springaop 包下、然后測試類就是Main類里面的aop()方法 ]

      @Component("dog")
      public class Dog {
          public Dog() {    }
          public void wangwang() {
              System.out.println("wangwang --- 狗");
          }
      }
      
      public interface Life {
          void create();
          void wangwang();
      }
      
      @Component(value = "lifeImpl")
      public class LifeImpl implements Life {
          @Override
          public void create() {
              System.out.println("[]--生命創建");
          }
          @Override
          public void wangwang() {
              System.out.println("[]--生命 汪汪汪");
          }
          public void wangwang( String msg ) {
              System.out.println("=========== " + msg);
              create(); wangwang();
              System.out.println("===========");
          }
      }
      // advice.java
      @Component
      @Aspect
      public class MyAdvice {
          private static final String dogExpression = "execution(* com.feng.springaop.*.wangwang*(..))";
          @Around(dogExpression)
          public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
              System.out.println("##########【DOG-環繞通知中的前置通知】##########");
              Object returnVale = joinPoint.proceed();
              System.out.println("##########【DOG-環繞通知中的后置通知】##########");
              return returnVale;
          }
      }
      // 一個普通的,沒有配置任何通知
      @Component
      public class Cat {
          public Cat() {   }
          public void miaomiao() {
              System.out.println("貓 喵喵");
          }
      }
      //Main.java
      @Configuration
      // @ComponentScan("com.feng.springioc") // 循環依賴分析 && IOC分析
      @ComponentScan("com.feng.springaop") // spring-aop分析
      @EnableAspectJAutoProxy
      //@EnableAspectJAutoProxy(proxyTargetClass = true) // cglib
      public class Main {
          public static void main(String[] args) {
              // xunhuan();
              aop();
          }
          public static void aop() {
              ApplicationContext context = new AnnotationConfigApplicationContext(Main.class);
              Dog dog = context.getBean("dog", Dog.class);
              dog.wangwang();
              System.out.println(dog.getClass().getName());
      
              Life impl = context.getBean("lifeImpl", Life.class);
              impl.wangwang();
              System.out.println(impl.getClass().getName());
              
              Cat cat = context.getBean("cat", Cat.class);
              cat.miaomiao();
              System.out.println(cat.getClass().getName());
          }
      }
      

      上面的示例代碼挺簡單的,運行上面的測試代碼,我們可以得到如下輸出:

      ##########【DOG-環繞通知中的前置通知】##########
      wangwang --- 狗
      ##########【DOG-環繞通知中的后置通知】##########
      com.feng.springaop.Dog$$EnhancerBySpringCGLIB$$563f1145
      ##########【DOG-環繞通知中的前置通知】##########
      []--生命 汪汪汪
      ##########【DOG-環繞通知中的后置通知】##########
      com.sun.proxy.$Proxy17
      貓 喵喵
      com.feng.springaop.Cat
      

      從輸出內容可以看到,dog對象的bean是走的cglib的動態代理,由于lifeImpl實現了接口,故其采用的是jdk動態代理,但是貓貓確實是一個實打實的我們的對象。

      動態代理不知道的可以看這篇文章:【動態代理】:https://blog.csdn.net/okok__TXF/article/details/144191784

      可以得知是創建了代理對象,然后執行就是將“通知”和實際“執行的邏輯”組合在一起了,那么我們就從SpringAOP 是如何創建代理對象、執行過程是什么樣子這兩個方面來分析一下其AOP。

      2.代理對象的創建

      在前一篇文章中,我們得知,代理對象的創建是在initializeBean(xx)方法里面進行的,我們來驗證一下:

      首先debug到cat對象的初始化:如下圖【在return的時候貓對象仍然是Cat類型的】

      然后再看dog對象的初始化:如下圖 【經過了圖中綠色下劃線之后,類型發生了變化CGLIB$$xxx的了】

      在看一下lifeImpl的初始化:如下圖 【經過了圖中綠色下劃線之后,類型發生了變化$Proxy的了】

      經過上面的對比:我們可以得知,代理對象的生成是在wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);里面的,此外如果實現了接口,那么就是jdk動態代理生成的代理對象、如果沒有實現接口,那么就是走的CGLIB生成的代理對象。

      目標很明確了,我們分析一下applyBeanPostProcessorsAfterInitialization方法就可以了。

      進入到這個方法里面,debug調試過后

      發現dog經過AnnotationAwareAspectJAutoProxyCreator.postProcessAfterInitialization(result, beanName) 方法之后,current就變成了 CGLIB的代理對象,說明這個方法大有奧秘!后面的lifeImpl對象亦是如此,就不給出圖片闡述了。那為什么cat前后還是cat呢,并沒有發生變化呢?

      // 實際上是到了下面的類的postProcessAfterInitialization方法
      // AbstractAutoProxyCreator.java 實現了BeanPostProcessor接口
      public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
      		implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
          @Override
          public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
              if (bean != null) {
                  Object cacheKey = getCacheKey(bean.getClass(), beanName);
                  // 檢查該 Bean 是否已被提前代理(如循環依賴中的早期引用)
                  if (this.earlyProxyReferences.remove(cacheKey) != bean) {
                      return wrapIfNecessary(bean, beanName, cacheKey);
                  }
              }
              return bean;
          }
      }
      

      postProcessAfterInitialization()方法是 BeanPostProcessor 接口的實現,作用于 Bean 初始化之后(如 @PostConstruct 執行后),主要用于處理 Spring AOP 的代理邏輯。其核心目標是確保 Bean 在初始化完成后,根據需要生成代理對象,同時避免重復代理(尤其是在存在循環依賴時)。

      此處的this.earlyProxyReferences.remove(cacheKey)就是從早期代理引用里面取出并移除該key的早期代理引用對象,來進行比對。這個earlyProxyReferences在哪里put呢?

      在IOC那一章里面,在屬性填充之前有這樣一段代碼,在三級緩存中添加了如下對象

      // 緩存早期單例,以便能夠解析循環引用
      boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
              isSingletonCurrentlyInCreation(beanName));
      if (earlySingletonExposure) {
          ....
          addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
      }
      
      // 這個getEarlyBeanReference,最后是來到了
      // AbstractAutoProxyCreator.java
      @Override
      public Object getEarlyBeanReference(Object bean, String beanName) {
          Object cacheKey = getCacheKey(bean.getClass(), beanName);
          this.earlyProxyReferences.put(cacheKey, bean); // 往早期代理引用放了一個對象--這里put的
          return wrapIfNecessary(bean, beanName, cacheKey);
      }
      // return的是wrapIfNecessary(bean, beanName, cacheKey)
      

      此章是沒有循環引用的,只有循環依賴的時候才會用到三級緩存里面的東西,也就是循環依賴的時候才會往earlyProxyReferences中put東西。為什么?見后續文章【spring循環依賴的解決】

      那么這里的earlyProxyReferences就肯定一直都是空的,故在AbstractAutoProxyCreator :: postProcessAfterInitialization() 方法里面會走

      if (this.earlyProxyReferences.remove(cacheKey) != bean) {
          return wrapIfNecessary(bean, beanName, cacheKey); // 走這里
      }
      

      這個wrapIfNecessary是什么,下面來看看

      protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
          //1. 如果該 Bean 已經被手動指定 TargetSource(如通過自定義 Scope),直接返回原始 Bean
          if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) 
              return bean;
          // 2. 如果緩存中標記該 Bean 不需要代理,直接返回
          if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) 
              return bean;
          // 3. 檢查是否為基礎設施類(如 Spring 內部類)或需要跳過代理的 Bean
          if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
              this.advisedBeans.put(cacheKey, Boolean.FALSE);
              return bean;
          }
          // 4. 獲取適用于該 Bean 的增強器(Advisors/Advices)**
          Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
          if (specificInterceptors != DO_NOT_PROXY) {
              // 標記該 Bean 需要代理
              this.advisedBeans.put(cacheKey, Boolean.TRUE);
              // 5.創建代理對象 **
              Object proxy = createProxy(
                      bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
              this.proxyTypes.put(cacheKey, proxy.getClass());// 緩存代理類型,后續可通過 getBean 直接返回代理對象
              return proxy;
          }
      	// 6. 無增強器,標記該 Bean 不需要代理
          this.advisedBeans.put(cacheKey, Boolean.FALSE);
          return bean;
      }
      

      一、獲取適用于該 Bean 的增強器:getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);

      // AbstractAdvisorAutoProxyCreator.java
      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();
      }
      // 只看比較重要的1 2兩點
      protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
          // 1.獲取候選Advisor
          List<Advisor> candidateAdvisors = findCandidateAdvisors();
          // 2.獲取適用于該bean的Advisor: 例如Pointcut匹配
          List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
          extendAdvisors(eligibleAdvisors); // 擴展
          if (!eligibleAdvisors.isEmpty()) {
              eligibleAdvisors = sortAdvisors(eligibleAdvisors); // 排序
          }
          return eligibleAdvisors;
      }
      
      
      //第1點:候選Advisor AnnotationAwareAspectJAutoProxyCreator.java
      @Override
      protected List<Advisor> findCandidateAdvisors() {
          // Add all the Spring advisors found according to superclass rules.
          List<Advisor> advisors = super.findCandidateAdvisors();
          // 為 Bean Factory 中的所有 AspectJ 方面構建 Advisor。
          if (this.aspectJAdvisorsBuilder != null) {
              advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors()); // 進入
          }
          return advisors;
      }
      //BeanFactoryAspectJAdvisorsBuilder.java
      public List<Advisor> buildAspectJAdvisors() {
          ...
          if (this.advisorFactory.isAspect(beanType)) { // @Aspect
              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 {
                  。。。
              }
          }
          ....
      }
      

      如圖,找到了我們的MyAdvice.

      // 第2點:獲取適用于該bean的Advisor -- 自己debug吧。。。
      // 我這就不給了,反正就是看candidateAdvisors匹不匹配嘛
      protected List<Advisor> findAdvisorsThatCanApply(
              List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
          ProxyCreationContext.setCurrentProxiedBeanName(beanName);
          try {
              return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
          }
          finally {
              ProxyCreationContext.setCurrentProxiedBeanName(null);
          }
      }
      

      在例子中,創建cat的時候,找不到合適的Advice,所以第二步就不會執行咯,故就不需要創建代理對象了

      二、創建代理對象 : createProxy(xxx, xx, xxx, xxx) 【本文就以cglib創建代理對象為主,jdk動態代理創建就由讀者自行調試分析了】

      createProxy 是 Spring AOP 中 創建代理對象的核心方法,位于 AbstractAutoProxyCreator 類中。它負責根據 Bean 的配置和增強器(Advice/Advisors)生成 JDK 動態代理或 CGLIB 代理對象

      // specificInterceptors就是第一步找到的advice中匹配該bean的東西,這里叫做攔截器
      protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
          @Nullable Object[] specificInterceptors, TargetSource targetSource) {
          ...
          if (proxyFactory.isProxyTargetClass()) {
          // 強制使用 CGLIB 代理 -- 
          if (Proxy.isProxyClass(beanClass) || ClassUtils.isLambdaClass(beanClass)) {
              // 處理已被 JDK 代理的類或 Lambda 表達式
              for (Class<?> ifc : beanClass.getInterfaces()) {
                  proxyFactory.addInterface(ifc); // 添加接口(確保引入增強器生效)
              }
          }
          } else {
              // 根據默認規則選擇代理類型
              if (shouldProxyTargetClass(beanClass, beanName)) {
                  // 如果是true-強制使用 CGLIB,即使目標類實現了接口
                  proxyFactory.setProxyTargetClass(true); // 強制 CGLIB
              } else {
                  evaluateProxyInterfaces(beanClass, proxyFactory); // 檢查接口決定代理類型
              }
          }
          ...
          //構建并添加增強器(Advisors)
          //將 specificInterceptors(如 MethodInterceptor)轉換為 Spring 的 Advisor 對象。
          Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
      	proxyFactory.addAdvisors(advisors);
          ...
          //選擇類加載器并生成代理
          ClassLoader classLoader = getProxyClassLoader();
          if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) {
              classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
          }
          return proxyFactory.getProxy(classLoader);
      }
      

      上面最后是return proxyFactory.getProxy(classLoader); --- 下面以dog對象為例子

      // CglibAopProxy.java
      @Override
      public Object getProxy(@Nullable ClassLoader classLoader) {
         try{
             ....
              // 配置 CGLIB 的 Enhancer 對象
              Enhancer enhancer = createEnhancer();
              if (classLoader != null) {// 設置類加載器
                  enhancer.setClassLoader(classLoader);
                  if (classLoader instanceof SmartClassLoader &&
                          ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
                      enhancer.setUseCache(false);
                  }
              }
              // 設置代理類的父類
              enhancer.setSuperclass(proxySuperClass);
              // 設置代理類要實現的接口
              enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
              enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
              enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));
      		// 獲取回調函數數組---------【重點1】
              Callback[] callbacks = getCallbacks(rootClass);
              Class<?>[] types = new Class<?>[callbacks.length];
              for (int x = 0; x < types.length; x++) {
                  types[x] = callbacks[x].getClass();
              }
              // 設置回調過濾器--------【重點2】
              enhancer.setCallbackFilter(new ProxyCallbackFilter(
                      this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
              enhancer.setCallbackTypes(types);
              // 生成代理類并創建代理實例 --------- 【重點3】
              return createProxyClassAndInstance(enhancer, callbacks);
         } ...
      }
      

      創建代理對象【重點1】getCallbacks(rootClass); 這個里面是什么呢?

      private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
      		// Parameters used for optimization choices...
      		boolean isFrozen = this.advised.isFrozen();
      		boolean exposeProxy = this.advised.isExposeProxy();
         		// 是否靜態類,這里的靜態并非指靜態類,而是每次調用返回的實例都是否是不可變的
      		// 如單例模式的bean就是靜態,而多例模式下的bean就不是靜態
      		boolean isStatic = this.advised.getTargetSource().isStatic();
      
      		// DynamicAdvisedInterceptor:用于處理包含 AOP 通知的方法調用,
      	    //它會根據配置的切面和通知邏輯來執行相應的增強操作。
          	//內部通過 ReflectiveMethodInvocation 鏈式調用通知邏輯。
      		Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
      
      		....
      		Callback[] mainCallbacks = new Callback[] {
      				aopInterceptor,  // for normal advice
      				targetInterceptor,  // 目標方法直接調用攔截器
      				new SerializableNoOp(),  // no override for methods mapped to this
      				targetDispatcher, this.advisedDispatcher,
      				new EqualsInterceptor(this.advised),// 處理代理對象的 equals 方法
      				new HashCodeInterceptor(this.advised)// 處理代理對象的 hashCode 方法
      		};
      
      		Callback[] callbacks;
      
      		// 如果類是靜態 && 配置凍結。則準備做一些優化策略
      		if (isStatic && isFrozen) {
      			Method[] methods = rootClass.getMethods();
      			Callback[] fixedCallbacks = new Callback[methods.length];
      			this.fixedInterceptorMap = CollectionUtils.newHashMap(methods.length);
      			// TODO: small memory optimization here (can skip creation for methods with no advice)
      			for (int x = 0; x < methods.length; x++) {
      				Method method = methods[x];
      				List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, rootClass);
      				fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
      						chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
      				this.fixedInterceptorMap.put(method, x);
      			}
      			callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];
      			System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);
      			System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length);
      			this.fixedInterceptorOffset = mainCallbacks.length;
      		}
      		else {
      			callbacks = mainCallbacks; //
      		}
      		return callbacks;
      	}
      

      創建代理對象【重點2】ProxyCallbackFilter 回調過濾器

      // Constants for CGLIB callback array indices
      private static final int AOP_PROXY = 0;
      private static final int INVOKE_TARGET = 1;
      private static final int NO_OVERRIDE = 2;
      private static final int DISPATCH_TARGET = 3;
      private static final int DISPATCH_ADVISED = 4;
      private static final int INVOKE_EQUALS = 5;
      private static final int INVOKE_HASHCODE = 6;
      
      public ProxyCallbackFilter(
      				AdvisedSupport advised, Map<Method, Integer> fixedInterceptorMap, int fixedInterceptorOffset) {
          this.advised = advised;
          this.fixedInterceptorMap = fixedInterceptorMap;
          this.fixedInterceptorOffset = fixedInterceptorOffset;
      }
      
      @Override
      public int accept(Method method) {
          // 1. 如果當前方法被 final 修飾,則不代理該方法
          //如果method 被 final 修飾,則無法代理
          if (AopUtils.isFinalizeMethod(method)) {
      		...
              return NO_OVERRIDE;
          }
          if (!this.advised.isOpaque() && method.getDeclaringClass().isInterface() &&
                  method.getDeclaringClass().isAssignableFrom(Advised.class)) {
              return DISPATCH_ADVISED;
          }
          // 3. equals 方法
          if (AopUtils.isEqualsMethod(method)) 
              ...
          // 4.hashCode
          if (AopUtils.isHashCodeMethod(method)) 
             ...
          Class<?> targetClass = this.advised.getTargetClass();
          List<?> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
          boolean haveAdvice = !chain.isEmpty();
          boolean isFrozen = this.advised.isFrozen();
          boolean exposeProxy = this.advised.isExposeProxy();
          boolean isStatic = this.advised.getTargetSource().isStatic();
          if (haveAdvice || !isFrozen) {
              if (exposeProxy) {
                  ...
                  return AOP_PROXY;
              }
              // Check to see if we have fixed interceptor to serve this method.
              // Else use the AOP_PROXY.
              if (isStatic && isFrozen && this.fixedInterceptorMap.containsKey(method)) {
                  ...
                  // We know that we are optimizing so we can use the FixedStaticChainInterceptors.
                  int index = this.fixedInterceptorMap.get(method);
                  return (index + this.fixedInterceptorOffset);
              }
              else {
                  return AOP_PROXY;
              }
          }
          else {
              if (exposeProxy || !isStatic) 
                  return INVOKE_TARGET;
              Class<?> returnType = method.getReturnType();
              if (targetClass != null && returnType.isAssignableFrom(targetClass)) {
                  ...
                  return INVOKE_TARGET;
              }
              else 
                  ..
                  return DISPATCH_TARGET;
          }
      }
      

      創建代理對象【重點3】生成代理類并創建代理實例 createProxyClassAndInstance(enhancer, callbacks);

      // ObjenesisCglibAopProxy.java
      @Override
      protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
          Class<?> proxyClass = enhancer.createClass();
          Object proxyInstance = null;
      
          if (objenesis.isWorthTrying()) {
              try {
                  //Objenesis 是一個專門用于繞過對象構造函數直接實例化對象的庫。
                  proxyInstance = objenesis.newInstance(proxyClass, enhancer.getUseCache());
              }
              .....
          }
      	// 當 Objenesis 失敗時,通過反射調用默認或指定參數的構造方法。
          if (proxyInstance == null) {
              // Regular instantiation via default constructor...
              try {
                  Constructor<?> ctor = (this.constructorArgs != null ?
                          proxyClass.getDeclaredConstructor(this.constructorArgTypes) :
                          proxyClass.getDeclaredConstructor());
                  ReflectionUtils.makeAccessible(ctor);
                  proxyInstance = (this.constructorArgs != null ?
                          ctor.newInstance(this.constructorArgs) : ctor.newInstance());
              }
              ....
          }
      	// 回調鏈決定了代理對象的方法攔截行為(如切面增強、直接調用目標方法等)。
          ((Factory) proxyInstance).setCallbacks(callbacks);
          return proxyInstance;
      }
      

      3.執行過程

      執行是怎么樣的呢?

      照樣從案例的執行開始看起

      public static void aop() {
          ApplicationContext context = new AnnotationConfigApplicationContext(Main.class);
          Dog dog = context.getBean("dog", Dog.class);
          dog.wangwang();
          System.out.println(dog.getClass().getName());
      
          Life impl = context.getBean("lifeImpl", Life.class);
          impl.wangwang();
          System.out.println(impl.getClass().getName());
      
          Cat cat = context.getBean("cat", Cat.class);
          cat.miaomiao();
          System.out.println(cat.getClass().getName());
      }
      

      先執行的dog的方法【cglib】、再執行impl的方法【jdk】,因為第一個沒有實現接口,第二個實現了接口。

      上一節我們可以知道是proxyFactory.getProxy(classLoader);創建的代理對象,實際上getProxy是AopProxy接口的方法,那么在Spring中該接口的直接實現類只有兩個:

      以第一個例子開頭,dog肯定是CglibAopProxy的代理對象。【代理不會的看這里】:http://www.rzrgm.cn/jackjavacpp/p/18582124

      熟悉cglib的都知道,通過cglib生成的代理對象,然后使用該對象執行目標方法,會走設置的方法攔截器,上一章最后創建代理對象那一節里面的getCallbacks方法,第一個就new了DynamicAdvisedInterceptor對象,它是用于處理包含 AOP 通知的方法調用。我們點開CglibAopProxy里面的DynamicAdvisedInterceptor靜態內部類看一下,肯定重寫了intercept方法,不用想啊,這就是會代理的好處啊。

      //CglibAopProxy.java的靜態內部類 DynamicAdvisedInterceptor
      //proxy:CGLIB 生成的代理對象。
      //method:被調用的方法(目標方法的反射對象)
      //args: 方法參數。
      //methodProxy:CGLIB 的 MethodProxy 對象,用于直接調用目標方法(比反射高效)
      public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
          Object oldProxy = null;
          boolean setProxyContext = false;
          Object target = null;
          //targetSource:目標對象來源(如單例、原型或池化對象)
          TargetSource targetSource = this.advised.getTargetSource();
          try {
              if (this.advised.exposeProxy) { //暴露代理到當前線程上下文
                  //允許目標對象內部方法通過 AopContext.currentProxy() 獲取代理對象,
                  //解決自調用(如 this.method())時 AOP 失效的問題。
                  oldProxy = AopContext.setCurrentProxy(proxy);
                  setProxyContext = true;
              }    
              target = targetSource.getTarget(); //獲取被代理的原始對象
              Class<?> targetClass = (target != null ? target.getClass() : null);
              List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
              Object retVal;
              // 無攔截器,直接調用目標方法
              if (chain.isEmpty() && CglibMethodInvocation.isMethodProxyCompatible(method)) {
                  Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                  retVal = invokeMethod(target, method, argsToUse, methodProxy);
              }
              else {
                  // 有攔截器,創建方法調用鏈并執行
                  //調用其 proceed() 方法,按順序執行攔截器鏈。
                  retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy)
                      .proceed();
              }
              retVal = processReturnType(proxy, target, method, retVal);
              return retVal;
          }
          finally {
              if (target != null && !targetSource.isStatic()) {
                  targetSource.releaseTarget(target);
              }
              if (setProxyContext) {
                  AopContext.setCurrentProxy(oldProxy); // 恢復原始代理上下文
              }
          }
      }
      
      public boolean equals()...
      public int hashCode()....
      }
      
      
      

      CglibMethodInvocation.java

      private static class CglibMethodInvocation extends ReflectiveMethodInvocation {
          @Override
          @Nullable
          public Object proceed() throws Throwable {
              try {
                  return super.proceed();
              }
              ....
          }
      }
      
      //ReflectiveMethodInvocation.java
      @Override
      @Nullable
      public Object proceed() throws Throwable {
          //從索引-1開始
          if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
              return invokeJoinpoint(); // 所有攔截器執行完畢,調用目標方法
          }
      	// 獲取下一個攔截器
          Object interceptorOrInterceptionAdvice =
                  this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
          //若獲取的攔截器是 InterceptorAndDynamicMethodMatcher 類型,需進行動態方法匹配
          if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
              // Evaluate dynamic method matcher here: static part will already have
              // been evaluated and found to match.
              InterceptorAndDynamicMethodMatcher dm =
                      (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
              Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
              //若匹配成功,調用攔截器的 invoke 方法,傳入當前 ReflectiveMethodInvocation 對象。
              //匹配就是在攔截器鏈執行過程中動態判斷當前攔截器是否需要應用于目標方法調用
              if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
                  return dm.interceptor.invoke(this);
              }
              else {
                  // 動態匹配失敗,跳過當前攔截器,遞歸調用 proceed 方法執行下一個攔截器
                  return proceed();
              }
          }
          else {
              // 不是動態方法匹配器,直接調用攔截器的 invoke 方法
              return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
          }
      }
      

      上面一個小小的方法就包含了

      1. 攔截器鏈模式
        通過責任鏈模式按順序執行攔截器,支持靈活擴展(如事務、日志、安全等)。
      2. 性能優化
        • 無攔截器時直接調用目標方法。
        • 使用 MethodProxy 代替反射調用。
      3. 上下文管理
        • AopContext 解決自調用問題。
        • TargetSource 管理目標對象的生命周期。

      4.案例分析

      下面就以@Transacional注解、自定義Advice相結合為例子,分析一下代理創建及其運行過程。

      首先搭建一個項目,如下:

      // 1.實體類對象
      @Data
      @AllArgsConstructor
      @NoArgsConstructor
      @TableName("user_tab")
      public class User {
          @TableId(type = IdType.AUTO)
          private Integer id;
          private String name;
          private BigDecimal account;
      }
      // 2.Mapper接口
      @Mapper
      public interface UserMapper extends BaseMapper<User> {
      }
      // 3.service
      @Service
      public class UserService {
          @Resource
          private UserMapper userMapper;
          @Transactional
          public void insertUser() {
              userMapper.insert(new User(null, "張三", new BigDecimal(100)));
              System.out.println("================業務操作--執行插入");
              //throw new RuntimeException("插入用戶失敗");
          }
      }
      //4.配置AOP 和 數據源 、事務管理器
      @Aspect
      @Component
      public class MyAdvice {
          private static final String userExpression = "execution(* com.feng.springCaseAnalysis.service.UserService.*(..))";
          @Before(userExpression)
          public void beforeAdvice() {
              System.out.println("Before通知 -- UserService 之前");
          }
      
          @Around(userExpression)
          public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
              System.out.println("環繞通知 -- UserService 之前");
              Object result = joinPoint.proceed();
              System.out.println("環繞通知 -- UserService 之后");
              return result;
          }
      }
      // 配置類
      @Configuration
      @MapperScan("com.feng.springCaseAnalysis.mapper")
      @EnableTransactionManagement
      public class DataProjectConfig {
          @Bean
          public DataSource dataSource() {
              // 創建數據源
              DruidDataSource dataSource = new DruidDataSource();
              dataSource.setUsername("root");
              dataSource.setPassword("123456");
              dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/spring_analysis?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai");
              dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
              dataSource.setInitialSize(5);
              return dataSource;
          }
          @Bean
          public MybatisSqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) {
              MybatisSqlSessionFactoryBean factoryBean = new MybatisSqlSessionFactoryBean();
              factoryBean.setDataSource(dataSource);
              return factoryBean;
          }
          // 事務管理器
          @Bean
          public DataSourceTransactionManager transactionManager(DataSource dataSource) {
              DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
              transactionManager.setDataSource(dataSource);
              return transactionManager;
          }
      }
      
      //5.Main測試
      @Configuration
      @ComponentScan("com.feng.springCaseAnalysis") // spring-- Transactional 結合 自定義 Advice 分析
      @EnableAspectJAutoProxy
      public class Main {
          public static void main(String[] args) {
              AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Main.class);
              UserService userService = context.getBean("userService", UserService.class);
              try {
                  userService.insertUser();
              } catch ( Exception e ) {
                  System.out.println("【Exception!!!】" + e.getMessage());
              }
          } 
      }
      

      在上面的案例搭建好之后,我們仔細分析一下UserService的代理創建過程:

      來到為UserService尋找advisor的這里,讀者們還記得這在哪個階段嗎?然后進入里面就是List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);

      如上圖所示,在候選的Advisors中,除了我們自定義的兩個Advisor,還找到了另外一個 BeanFactoryTransactionAttributeSourceAdvisor,它也是一個PointCutAdvisor。在調用canApply( )方法的時候,會解析UserService所有方法上面有沒有@Transactional注解,并解析里面的屬性,這里insertUser方法有@Transactional注解,故匹配上了。

      @Override
      public boolean matches(Method method, Class<?> targetClass) {
          /*
          method: com.feng.springCaseAnalysis.service.UserService.insertUser
          targetClass: class com.feng.springCaseAnalysis.service.UserService
          */
          
          // 這里的tas是AnnotationTransactionAttributeSource
          TransactionAttributeSource tas = getTransactionAttributeSource();
          return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
      }
      

      所以elibibAdvisors都匹配上了,此時的elibibAdvisors里面有三個Advisor。然后創建代理對象,設置CallBack那些就同理了,如下圖所示。

      然后就返回代理對象咯。

      可以看到經過applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);之后,WrapperBean變成了UserService$$EnhancerBySpringCGLIB$$a768552c@4109代理對象了。

      執行就很簡單了:

      遞歸調用嘛。

      // TransactionInterceptor.java
      @Override
      @Nullable
      public Object invoke(MethodInvocation invocation) throws Throwable {
          // Work out the target class: may be {@code null}.
          // The TransactionAttributeSource should be passed the target class
          // as well as the method, which may be from an interface.
          Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
      
          // Adapt to TransactionAspectSupport's invokeWithinTransaction...
          return invokeWithinTransaction(invocation.getMethod(), targetClass, new CoroutinesInvocationCallback() {
              @Override
              @Nullable
              public Object proceedWithInvocation() throws Throwable {
                  return invocation.proceed();
              }
              @Override
              public Object getTarget() {
                  return invocation.getThis();
              }
              @Override
              public Object[] getArguments() {
                  return invocation.getArguments();
              }
          });
      }
      // invocation是一個函數式接口,proceedWithInvocation實際上就是上面的invocation.proceed(),這樣就完成了遞歸調用了
      protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
      			final InvocationCallback invocation) throws Throwable {
          ....
          PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
          final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
      
          if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
              TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
              Object retVal;
              try {
                  // 調用下一層
                  retVal = invocation.proceedWithInvocation();
              }
              catch (Throwable ex) { // 捕獲到異常了
                  // 在里面判斷一些條件,然后事務回滾
                  completeTransactionAfterThrowing(txInfo, ex);
                  throw ex;
              }
              finally {
                  cleanupTransactionInfo(txInfo);
              }
              if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
                  // Set rollback-only in case of Vavr failure matching our rollback rules...
                  TransactionStatus status = txInfo.getTransactionStatus();
                  if (status != null && txAttr != null) {
                      retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
                  }
              }
              commitTransactionAfterReturning(txInfo); // 提交事務
              return retVal;
          }
      

      5.思考題: @Import注解

      本章案例見importCase包:

      為什么在第四章案例中,多了那么多和Transactional的bean?在配置類@EnableTransactionManagement這個是干嘛的?

      @Target(ElementType.TYPE)
      @Retention(RetentionPolicy.RUNTIME)
      @Documented
      @Import(TransactionManagementConfigurationSelector.class) // 有這個注解
      public @interface EnableTransactionManagement {
          ....
      }
      

      這個@Import注解的作用:@Import只能用在類上 ,@Import通過快速導入的方式實現把實例加入spring的IOC容器中。

      ①主要用法:

      1.直接填class數組: bean名稱是該類的全類名

      // 主測試類
      ApplicationContext context = new AnnotationConfigApplicationContext(Main.class);
      Student bean = context.getBean(Student.class);
      for (String name : context.getBeanDefinitionNames()) {
          System.out.println(name);
      }
      System.out.println("========");
      System.out.println(bean);
      // 配置類
      @Configuration
      @Import({Student.class})
      public class Config {
      }
      // Student并沒有被Spring管理,
      // 但是通過@Import導進去了
      @Data
      @AllArgsConstructor
      @NoArgsConstructor
      public class Student {
          private String name = "asd";
          private Integer age = 10;
      }
      

      運行結果如下:

      org.springframework.context.annotation.internalConfigurationAnnotationProcessor
      org.springframework.context.annotation.internalAutowiredAnnotationProcessor
      org.springframework.context.annotation.internalCommonAnnotationProcessor
      org.springframework.context.event.internalEventListenerProcessor
      org.springframework.context.event.internalEventListenerFactory
      main
      config
      com.feng.importCase.Student //看這里!!!!
      org.springframework.aop.config.internalAutoProxyCreator
      ========
      Student(name=asd, age=10)
      

      2.ImportSelector方式【SpringBoot中用的很多】

      @Configuration
      //@Import({Student.class})
      @Import({MyStudentImportSelector.class})
      public class Config {
      }
      
      //MyStudentImportSelector.java
      public class MyStudentImportSelector implements ImportSelector {
          //參數: AnnotationMetadata表示當前被@Import注解給標注的所有注解信息
          @Override
          public String[] selectImports(AnnotationMetadata importingClassMetadata) {
              return new String[]{"com.feng.importCase.Student"};
          }
      }
      

      配置類改成導入Selector,需要導入的類,在該Selector中給出來,這樣就可以把我的Student類導進容器里面了。

      3.ImportBeanDefinitionRegistrar方式

      同樣是一個接口,類似于第二種ImportSelector用法,只不過這種用法更加地自定義化注冊

      public class StudentImportRegistrar implements ImportBeanDefinitionRegistrar {
          @Override
          public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
              RootBeanDefinition beanDefinition = new RootBeanDefinition(Student.class);
              registry.registerBeanDefinition("haha-student", beanDefinition);
          }
      }
      
      @Configuration
      //@Import({Student.class})
      //@Import({MyStudentImportSelector.class})
      @Import({StudentImportRegistrar.class})
      public class Config {
      }
      

      ②源碼解析

      @Import是在下面這一步起作用的。

       refresh()里面往下 ---->
      // Invoke factory processors registered as beans in the context.
      invokeBeanFactoryPostProcessors(beanFactory); ---->
      |    
      PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
      |
      invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
      

      待讀者自行分析把。嘿嘿嘿

      end.參考

      1. https://blog.csdn.net/qq_36882793/article/details/119823785 【cglib 的代理過程】
      2. http://www.rzrgm.cn/yichunguo/p/12122598.html 【import】
      posted @ 2025-04-21 17:05  別來無恙?  閱讀(321)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 乌克兰丰满女人a级毛片右手影院| 国产91精品调教在线播放| 久青草视频在线免费观看| 9丨精品国产高清自在线看| 久久久久噜噜噜亚洲熟女综合| 国产成人女人在线观看| 制服丝袜人妻有码无码中文字幕| 潼关县| 亚洲一区二区三区黄色片| 国产欧美日韩亚洲一区二区三区| 国产精品一区二区中文| 成人性生交片无码免费看| 一区二区在线欧美日韩中文| 亚洲av色香蕉一区二区| 亚洲中文久久久久久精品国产| 蜜桃臀av在线一区二区| 国产欧美日韩亚洲一区二区三区| 99久久精品国产一区二区蜜芽| 久久国产精品波多野结衣| yy111111在线尤物| 国产午夜在线观看视频播放| 少妇被躁爽到高潮| 在线观看中文字幕国产码| 国产高清在线男人的天堂| 亚洲一二区制服无码中字| 一区天堂中文最新版在线| 麻豆精品在线| 国产一区二区三区在线观| 国产成人精品视频不卡| 国产中文字幕一区二区| 人人做人人妻人人精| a男人的天堂久久a毛片| 国产成人无码A区在线观看视频| 少妇人妻偷人精品无码视频新浪 | 色综合色综合久久综合频道| 久久精品无码免费不卡| 人妻丝袜AV中文系列先锋影音| 成人亚洲一级午夜激情网| 精品一区二区三区在线观看l| 樱桃视频影院在线播放| 国产一区二区三区小说|