Spring-AOP分析

AOP都知道,是spring中的面向切面編程,就是可以把我們寫的代碼橫向擴展,而且又不會影響原來的代碼結構,是一種思想。說白了就是可以在你想實現什麼功能的前後能夠搞一些事情。底層使用的是JDK和Cglib動態代理

爲什麼要使用AOP呢:
1、AOP採用了橫向的抽取機制,取代了傳統縱向繼承體系重複性代碼結構
2、可以在不修改源代碼的前提下,對程序功能進行增強

主要的幾種的方式:
1、前置通知:@Before 在我們執行目標方法前運行
2、後置通知:@After 在我們目標方法運行之後運行,不管有沒有異常
3、後置返回通知:@AfterReturning 在我們的目標方法正常返回值之後運行
4、異常通知:@AfterThrowing 在我們執行目標方法出現異常之後運行
5、環繞通知:@Around 前置 > @Before +後置 < @After(正常) 動態代理,必須手動執行目標方法

註解實現AOP

先創建一個Service和接口類

public interface UserService {
    public String selectUserName();
}
@Service("userService")
public class UserServiceImp implements UserService {
    @Override
    public String selectUserName() {
        String name = "zx";
        return name;
    }
}

創建實體類

public class UserEntity {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

創建一個控制層

@RestController
@RequestMapping("/aop")
public class UserController {
    @Autowired
    private UserService userService;
    @GetMapping("/aoptest")
    public void UserTest(){
        System.out.println("UserServiceImp方法");
        userService.selectUserName();
    }
}

創建代理的配置類。把bean注入到容器中

@Configuration
@EnableAspectJAutoProxy
public class UserConfig{
        /**
         * 把目標類註冊到spring容器中去
         * @return
         */
        @Bean
        public UserService userService(){
            return new UserService() {
                @Override
                public String selectUserName() {
                    String name = "配置類實例";
                    return name;
                }
            };
        }

        /**
         * 註冊切面類到spring容器中去
         * @return
         */
        @Bean
        public UserPointCut servantAspects02(){
            return new UserPointCut();
        }
}

再創建一個切面類

@Aspect
@Component
public class UserPointCut {
    @Pointcut("execution(* com.zx.springaop.service..*(..))")
    public void UserPointCut(){}

    @Before("UserPointCut()")
    public void BeforUser(){
        System.out.println("前置");
    }

    @After("UserPointCut()")
    public void AfterUser(){
        System.out.println("後置");
    }

    @AfterReturning("UserPointCut()")
    public void AfterReturning(){
        System.out.println("後置返回");
    }
    @AfterThrowing(value = "UserPointCut()",throwing = "ex")
    public void AfterThreadExction(Exception ex){
        System.out.println("後置異常拋出"+ex);
    }

    @Around("UserPointCut()")
    public Object AroudUserCut(ProceedingJoinPoint pjd)  {
        Object result=null;
        String methodName=pjd.getSignature().getName();//方法名
        try {
            //前置通知
            System.out.println("the method "+methodName+" begins with "+Arrays.asList(pjd.getArgs()));
            result=pjd.proceed();
            //結果通知
            System.out.println("the method"+methodName+" ends "+result);
        } catch (Throwable e) {
            //異常通知
            System.out.println("the method "+methodName+" occurs execption:"+e);
            throw new RuntimeException(e);
        }
        //後置通知
        System.out.println("the method "+methodName+" ends");
        return result;
    }
}

最後創建一個測試類

public class UserPointCutTest {
    public static void main(String args[]){
        AnnotationConfigApplicationContext acc = new AnnotationConfigApplicationContext(UserConfig.class);
        UserService userService = (UserService) acc.getBean(UserService.class);
        userService.selectUserName();
    }
}

輸出:
在這裏插入圖片描述
——————————————————————————————
下面開始分析。
所謂的jdk動態代理或者是CGLib動態代理完全取決於
打斷點,看debug模式,

可以看到現在是JDK的動態代理模式,那麼怎麼可以轉變成CGLib呢,
在這裏插入圖片描述
狀態改爲true就是強制使用CGLib動態代理了。說白了就是把有沒有接口。有接口就是JDK,沒有就默認CGLib
在這裏插入圖片描述
流程分析:

將bean導入spring容器AspectJAutoProxyRegistrar->ImportBeanDefinitionRegistrar#registerBeanDefinitions

將bean註冊到spring容器 AnnotationAwareAspectJAutoProxyCreator className: org.springframework.aop.config.internalAutoProxyCreator class: 根據spring提供的規範構建spring bean RootBeanDefinition

上面構建 AnnotationAwareAspectJAutoProxyCreator 這個bean 然後這個bean實現InstantiationAwareBeanPostProcessor接口
該接口實現BeanPostProcessor接口 BeanPostProcessor是spring提供的擴展接口 在bean實例的時候回調 --》postProcessAfterInitialization

然後就會找所有的Advisor
1、 第一步: 先找父類時候有實現Advisor的接口。
2、 第二步: 然後找到所有類上面註解標註爲@Aspect, 然後解析該類標註Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class

AOP的 實現方式很簡單,就是動態代理。就是在實例化的時候生成代理類,來替換掉真實實現類來對外提供服務。就是在getBean(…)的時候返回的其實是代理類的一個實例,而這個代理類就是JDK活着CGLib動態生成的,(spring-aop只能在Spring中才能實現。)

先看一下 DefaultAdvisorAutoProxyCreator類中的BeanPostProcessor方法。在IOC中,這個方法是在init-method前後執行的。

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

回顧一下IOC:

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
            throws BeanCreationException {
 
    // Instantiate the bean.
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    if (instanceWrapper == null) {
        // 1. 創建實例
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    ...
 
    // Initialize the bean instance.
    Object exposedObject = bean;
    try {
        // 2. 裝載屬性
        populateBean(beanName, mbd, instanceWrapper);
        if (exposedObject != null) {
            // 3. 初始化
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
    }
    ...
}

在第三步,初始化Bean,會調用BeanPostProcessor()方法

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
   ...
   Object wrappedBean = bean;
   if (mbd == null || !mbd.isSynthetic()) {
      // 1. 執行每一個 BeanPostProcessor 的 postProcessBeforeInitialization 方法
      wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
   }
 
   try {
      // 調用 bean 配置中的 init-method="xxx"
      invokeInitMethods(beanName, wrappedBean, mbd);
   }
   ...
   if (mbd == null || !mbd.isSynthetic()) {
      // 我們關注的重點是這裏!!!
      // 2. 執行每一個 BeanPostProcessor 的 postProcessAfterInitialization 方法
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
   }
   return wrappedBean;
}

也就是說,Spring AOP 會在 IOC 容器創建 bean 實例的最後對 bean 進行處理。其實就是在這一步進行代理增強。

DefaultAdvisorAutoProxyCreator 的繼承結構中,postProcessAfterInitialization() 方法在其父類 AbstractAutoProxyCreator 這一層被覆寫了:

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
   if (bean != null) {
      Object cacheKey = getCacheKey(bean.getClass(), beanName);
      if (!this.earlyProxyReferences.contains(cacheKey)) {
         return wrapIfNecessary(bean, beanName, cacheKey);
      }
   }
   return bean;
}

看wrapifnecessary方法。會返回一個代理類


protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
   if (beanName != null && 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;
   }
 
   // 返回匹配當前 bean 的所有的 advisor、advice、interceptor
   // 對於本文的例子,"userServiceImpl" 和 "OrderServiceImpl" 這兩個 bean 創建過程中,
   //   到這邊的時候都會返回兩個 advisor
   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;
}

在看 createProxy(…)方法,創建代理類:


// 注意看這個方法的幾個參數,
//   第三個參數攜帶了所有的 advisors
//   第四個參數 targetSource 攜帶了真實實現的信息
protected Object createProxy(
      Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
 
   if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
      AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
   }
 
   // 創建 ProxyFactory 實例
   ProxyFactory proxyFactory = new ProxyFactory();
   proxyFactory.copyFrom(this);
 
   // 在 schema-based 的配置方式中,我們介紹過,如果希望使用 CGLIB 來代理接口,可以配置
   // proxy-target-class="true",這樣不管有沒有接口,都使用 CGLIB 來生成代理:
   //   <aop:config proxy-target-class="true">......</aop:config>
   if (!proxyFactory.isProxyTargetClass()) {
      if (shouldProxyTargetClass(beanClass, beanName)) {
         proxyFactory.setProxyTargetClass(true);
      }
      else {
         // 點進去稍微看一下代碼就知道了,主要就兩句:
         // 1. 有接口的,調用一次或多次:proxyFactory.addInterface(ifc);
         // 2. 沒有接口的,調用:proxyFactory.setProxyTargetClass(true);
         evaluateProxyInterfaces(beanClass, proxyFactory);
      }
   }
 
   // 這個方法會返回匹配了當前 bean 的 advisors 數組
   // 對於本文的例子,"userServiceImpl" 和 "OrderServiceImpl" 到這邊的時候都會返回兩個 advisor
   // 注意:如果 specificInterceptors 中有 advice 和 interceptor,它們也會被包裝成 advisor,進去看下源碼就清楚了
   Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
   for (Advisor advisor : advisors) {
      proxyFactory.addAdvisor(advisor);
   }
 
   proxyFactory.setTargetSource(targetSource);
   customizeProxyFactory(proxyFactory);
 
   proxyFactory.setFrozen(this.freezeProxy);
   if (advisorsPreFiltered()) {
      proxyFactory.setPreFiltered(true);
   }
 
   return proxyFactory.getProxy(getProxyClassLoader());
}

這個方法主要是在內部創建了一個 ProxyFactory 的實例,然後 set 了一大堆內容,剩下的工作就都是這個 ProxyFactory 實例的了,通過這個實例來創建代理: getProxy(classLoader)。

看看代理類

public Object getProxy(ClassLoader classLoader) {
   return createAopProxy().getProxy(classLoader);
}

通過創建代理類來生成aop代理

protected final synchronized AopProxy createAopProxy() {
   if (!this.active) {
      activate();
   }
   return getAopProxyFactory().createAopProxy(this);
}

創建 AopProxy 之前,我們需要一個 AopProxyFactory 實例,然後看 ProxyCreatorSupport 的構造方法:

public ProxyCreatorSupport() {
   this.aopProxyFactory = new DefaultAopProxyFactory();
}

看DefaultAopProxyFactory 這個類,我們看它的 createAopProxy(…) 方法:

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
 
   @Override
   public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
      // (我也沒用過這個optimize,默認false) || (proxy-target-class=true) || (沒有接口)
      if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
         Class<?> targetClass = config.getTargetClass();
         if (targetClass == null) {
            throw new AopConfigException("TargetSource cannot determine target class: " +
                  "Either an interface or a target is required for proxy creation.");
         }
         // 如果要代理的類本身就是接口,也會用 JDK 動態代理
         // 我也沒用過這個。。。
         if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
            return new JdkDynamicAopProxy(config);
         }
         return new ObjenesisCglibAopProxy(config);
      }
      else {
         // 如果有接口,會跑到這個分支
         return new JdkDynamicAopProxy(config);
      }
   }
   // 判斷是否有實現自定義的接口
   private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
      Class<?>[] ifcs = config.getProxiedInterfaces();
      return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
   }
 
}

這就有可能返回jdk,也有可能返回cglib,然後下面就分別是jdk和cglib的源碼,最後各自集成各自的攔截類,進行代理

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章