【技術實踐】基於Cglib動態代理,實現Spring的AOP核心功能!

做者:小傅哥
博客:https://bugstack.cnhtml

沉澱、分享、成長,讓本身和他人都能有所收穫!😄

1、前言

爲何,你的代碼老是糊到豬圈上?java

🎙怎麼辦,知道你在互聯網,不知道你在哪一個大廠。知道你在加班,不知道你在和哪一個產品爭辯。知道你在偷懶,不知道你要摸魚到幾點。知道你在搬磚,不知道你在蓋哪一個豬圈。spring


當你特別辛苦夜以繼日的完成着,天天、每週、每個月重複性的工做時,你能得到的成長是最小,獲得的回報也是少的。留着最多的汗、拿着最少的錢數據庫

可能你一激動開始看源碼,但不知道看完的源碼能用到什麼地方。看設計模式,看的時候懂,但改本身的代碼又下不去手。其實一方面是自己技術棧的知識面不足,另一方面是本身儲備的代碼也不夠。最終也就致使根本無法把一些列的知識串聯起來,就像你看了 HashMap,但也聯想不到分庫分表組件中的數據散列也會用到了 HashMap 中的擾動函數思想和泊松分佈驗證看了Spring 源碼,也讀不出來 Mybatis 是如何解決只定義 Dao 接口就能使用配置或者註解對數據庫進行 CRUD 操做看來 JDK 的動態代理,也想不到 AOP 是如何設計的。因此成體系學習,增強技術棧知識的完整性,才能更好的用上這些學習到的編碼能力。express

2、目標

到本章節咱們將要從 IOC 的實現,轉入到關於 AOP(Aspect Oriented Programming) 內容的開發。在軟件行業,AOP 意爲:面向切面編程,經過預編譯的方式和運行期間動態代理實現程序功能功能的統一維護。其實 AOP 也是 OOP 的延續,在 Spring 框架中是一個很是重要的內容,使用 AOP 能夠對業務邏輯的各個部分進行隔離,從而使各模塊間的業務邏輯耦合度下降,提升代碼的可複用性,同時也能提升開發效率。編程

關於 AOP 的核心技術實現主要是動態代理的使用,就像你能夠給一個接口的實現類,使用代理的方式替換掉這個實現類,使用代理類來處理你須要的邏輯。好比:segmentfault

@Test
public void test_proxy_class() {
    IUserService userService = (IUserService) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{IUserService.class}, (proxy, method, args) -> "你被代理了!");
    String result = userService.queryUserInfo();
    System.out.println("測試結果:" + result);
}

代理類的實現基本都你們都見過,那麼有了一個基本的思路後,接下來就須要考慮下怎麼給方法作代理呢,而不是代理類。另外怎麼去代理全部符合某些規則的全部類中方法呢。若是能夠代理掉全部類的方法,就能夠作一個方法攔截器,給全部被代理的方法添加上一些自定義處理,好比打印日誌、記錄耗時、監控異常等。設計模式

3、方案

在把 AOP 整個切面設計融合到 Spring 前,咱們須要解決兩個問題,包括:如何給符合規則的方法作代理以及作完代理方法的案例後,把類的職責拆分出來。而這兩個功能點的實現,都是以切面的思想進行設計和開發。若是不是很清楚 AOP 是啥,你能夠把切面理解爲用刀切韭菜,一根一根切老是有點慢,那麼用手(代理)把韭菜捏成一把,用菜刀或者斧頭這樣不一樣的攔截操做來處理。而程序中其實也是同樣,只不過韭菜變成了方法,菜刀變成了攔截方法。總體設計結構以下圖:架構

  • 就像你在使用 Spring 的 AOP 同樣,只處理一些須要被攔截的方法。在攔截方法後,執行你對方法的擴展操做。
  • 那麼咱們就須要先來實現一個能夠代理方法的 Proxy,其實代理方法主要是使用到方法攔截器類處理方法的調用 MethodInterceptor#invoke,而不是直接使用 invoke 方法中的入參 Method method 進行 method.invoke(targetObj, args) 這塊是整個使用時的差別。
  • 除了以上的核心功能實現,還須要使用到 org.aspectj.weaver.tools.PointcutParser 處理攔截表達式 "execution(* cn.bugstack.springframework.test.bean.IUserService.*(..))",有了方法代理和處理攔截,咱們就能夠完成設計出一個 AOP 的雛形了。

4、實現

1. 工程結構

![spring-12-02](https://bugstack.cn/assets/images/spring/spring-12-02.png)![spring-12-02](https://bugstack.cn/assets/images/spring/spring-12-02.png)small-spring-step-11
└── src
    ├── main
    │   └── java
    │       └── cn.bugstack.springframework
    │           ├── aop
    │           │   ├── aspectj
    │           │   │   └── AspectJExpressionPointcut.java
    │           │   ├── framework 
    │           │   │   ├── AopProxy.java
    │           │   │   ├── Cglib2AopProxy.java
    │           │   │   ├── JdkDynamicAopProxy.java
    │           │   │   └── ReflectiveMethodInvocation.java
    │           │   ├── AdvisedSupport.java
    │           │   ├── ClassFilter.java
    │           │   ├── MethodMatcher.java
    │           │   ├── Pointcut.java
    │           │   └── TargetSource.java
    │           ├── beans
    │           │   ├── factory
    │           │   │   ├── config
    │           │   │   │   ├── AutowireCapableBeanFactory.java
    │           │   │   │   ├── BeanDefinition.java
    │           │   │   │   ├── BeanFactoryPostProcessor.java
    │           │   │   │   ├── BeanPostProcessor.java
    │           │   │   │   ├── BeanReference.java
    │           │   │   │   ├── ConfigurableBeanFactory.java
    │           │   │   │   └── SingletonBeanRegistry.java
    │           │   │   ├── support
    │           │   │   │   ├── AbstractAutowireCapableBeanFactory.java
    │           │   │   │   ├── AbstractBeanDefinitionReader.java
    │           │   │   │   ├── AbstractBeanFactory.java
    │           │   │   │   ├── BeanDefinitionReader.java
    │           │   │   │   ├── BeanDefinitionRegistry.java
    │           │   │   │   ├── CglibSubclassingInstantiationStrategy.java
    │           │   │   │   ├── DefaultListableBeanFactory.java
    │           │   │   │   ├── DefaultSingletonBeanRegistry.java
    │           │   │   │   ├── DisposableBeanAdapter.java
    │           │   │   │   ├── FactoryBeanRegistrySupport.java
    │           │   │   │   ├── InstantiationStrategy.java
    │           │   │   │   └── SimpleInstantiationStrategy.java  
    │           │   │   ├── support
    │           │   │   │   └── XmlBeanDefinitionReader.java
    │           │   │   ├── Aware.java
    │           │   │   ├── BeanClassLoaderAware.java
    │           │   │   ├── BeanFactory.java
    │           │   │   ├── BeanFactoryAware.java
    │           │   │   ├── BeanNameAware.java
    │           │   │   ├── ConfigurableListableBeanFactory.java
    │           │   │   ├── DisposableBean.java
    │           │   │   ├── FactoryBean.java
    │           │   │   ├── HierarchicalBeanFactory.java
    │           │   │   ├── InitializingBean.java
    │           │   │   └── ListableBeanFactory.java
    │           │   ├── BeansException.java
    │           │   ├── PropertyValue.java
    │           │   └── PropertyValues.java 
    │           ├── context
    │           │   ├── event
    │           │   │   ├── AbstractApplicationEventMulticaster.java 
    │           │   │   ├── ApplicationContextEvent.java 
    │           │   │   ├── ApplicationEventMulticaster.java 
    │           │   │   ├── ContextClosedEvent.java 
    │           │   │   ├── ContextRefreshedEvent.java 
    │           │   │   └── SimpleApplicationEventMulticaster.java 
    │           │   ├── support
    │           │   │   ├── AbstractApplicationContext.java 
    │           │   │   ├── AbstractRefreshableApplicationContext.java 
    │           │   │   ├── AbstractXmlApplicationContext.java 
    │           │   │   ├── ApplicationContextAwareProcessor.java 
    │           │   │   └── ClassPathXmlApplicationContext.java 
    │           │   ├── ApplicationContext.java 
    │           │   ├── ApplicationContextAware.java 
    │           │   ├── ApplicationEvent.java 
    │           │   ├── ApplicationEventPublisher.java 
    │           │   ├── ApplicationListener.java 
    │           │   └── ConfigurableApplicationContext.java
    │           ├── core.io
    │           │   ├── ClassPathResource.java 
    │           │   ├── DefaultResourceLoader.java 
    │           │   ├── FileSystemResource.java 
    │           │   ├── Resource.java 
    │           │   ├── ResourceLoader.java 
    │           │   └── UrlResource.java
    │           └── utils
    │               └── ClassUtils.java
    └── test
        └── java
            └── cn.bugstack.springframework.test
                ├── bean
                │   ├── IUserService.java
                │   ├── UserService.java
                │   └── UserServiceInterceptor.java
                └── ApiTest.java

工程源碼公衆號「bugstack蟲洞棧」,回覆:Spring 專欄,獲取完整源碼app

AOP 切點表達式和使用以及基於 JDK 和 CGLIB 的動態代理類關係,如圖 12-2

圖 12-2

  • 整個類關係圖就是 AOP 實現核心邏輯的地方,上面部分是關於方法的匹配實現,下面從 AopProxy 開始是關於方法的代理操做。
  • AspectJExpressionPointcut 的核心功能主要依賴於 aspectj 組件並處理 Pointcut、ClassFilter,、MethodMatcher 接口實現,專門用於處理類和方法的匹配過濾操做。
  • AopProxy 是代理的抽象對象,它的實現主要是基於 JDK 的代理和 Cglib 代理。在前面章節關於對象的實例化 CglibSubclassingInstantiationStrategy,咱們也使用過 Cglib 提供的功能。

2. 代理方法案例

在實現 AOP 的核心功能以前,咱們先作一個代理方法的案例,經過這樣一個能夠歸納代理方法的核心全貌,可讓你們更好的理解後續拆解各個方法,設計成解耦功能的 AOP 實現過程。

單元測試

@Test
public void test_proxy_method() {
    // 目標對象(能夠替換成任何的目標對象)
    Object targetObj = new UserService();
    // AOP 代理
    IUserService proxy = (IUserService) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), targetObj.getClass().getInterfaces(), new InvocationHandler() {
        // 方法匹配器
        MethodMatcher methodMatcher = new AspectJExpressionPointcut("execution(* cn.bugstack.springframework.test.bean.IUserService.*(..))");
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if (methodMatcher.matches(method, targetObj.getClass())) {
                // 方法攔截器
                MethodInterceptor methodInterceptor = invocation -> {
                    long start = System.currentTimeMillis();
                    try {
                        return invocation.proceed();
                    } finally {
                        System.out.println("監控 - Begin By AOP");
                        System.out.println("方法名稱:" + invocation.getMethod().getName());
                        System.out.println("方法耗時:" + (System.currentTimeMillis() - start) + "ms");
                        System.out.println("監控 - End\r\n");
                    }
                };
                // 反射調用
                return methodInterceptor.invoke(new ReflectiveMethodInvocation(targetObj, method, args));
            }
            return method.invoke(targetObj, args);
        }
    });
    String result = proxy.queryUserInfo();
    System.out.println("測試結果:" + result);
}
  • 首先整個案例的目標是給一個 UserService 當成目標對象,對類中的全部方法進行攔截添加監控信息打印處理。
  • 從案例中你能夠看到有代理的實現 Proxy.newProxyInstance,有方法的匹配 MethodMatcher,有反射的調用 invoke(Object proxy, Method method, Object[] args),也用用戶本身攔截方法後的操做。這樣一看其實和咱們使用的 AOP 就很是相似了,只不過你在使用 AOP 的時候是框架已經提供更好的功能,這裏是把全部的核心過程給你展現出來了。

測試結果

監控 - Begin By AOP
方法名稱:queryUserInfo
方法耗時:86ms
監控 - End

測試結果:小傅哥,100001,深圳

Process finished with exit code 0
  • 從測試結果能夠看到咱們已經對 UserService#queryUserInfo 方法進行了攔截監控操做,其實後面咱們實現的 AOP 就是如今體現出的結果,只不過咱們須要把這部分測試的案例解耦爲更具備擴展性的各個模塊實現。

拆解案例

圖 12-3

  • 拆解過程能夠參考截圖 12-3,咱們須要把代理對象拆解出來,由於它能夠是 JDK 的實現也能夠是 Cglib 的處理。
  • 方法匹配器操做其實已是一個單獨的實現類了,不過咱們還須要把傳入的目標對象、方法匹配、攔截方法,都進行統一的包裝,方便外部調用時進行一個入參透傳。
  • 最後實際上是 ReflectiveMethodInvocation 的使用,它目前已是實現 MethodInvocation 接口的一個包裝後的類,參數信息包括:調用的對象、調用的方法、調用的入參。

3. 切點表達式

定義接口

cn.bugstack.springframework.aop.Pointcut

public interface Pointcut {

    /**
     * Return the ClassFilter for this pointcut.
     * @return the ClassFilter (never <code>null</code>)
     */
    ClassFilter getClassFilter();

    /**
     * Return the MethodMatcher for this pointcut.
     * @return the MethodMatcher (never <code>null</code>)
     */
    MethodMatcher getMethodMatcher();

}
  • 切入點接口,定義用於獲取 ClassFilter、MethodMatcher 的兩個類,這兩個接口獲取都是切點表達式提供的內容。

cn.bugstack.springframework.aop.ClassFilter

public interface ClassFilter {

    /**
     * Should the pointcut apply to the given interface or target class?
     * @param clazz the candidate target class
     * @return whether the advice should apply to the given target class
     */
    boolean matches(Class<?> clazz);

}
  • 定義類匹配類,用於切點找到給定的接口和目標類。

cn.bugstack.springframework.aop.MethodMatcher

public interface MethodMatcher {

    /**
     * Perform static checking whether the given method matches. If this
     * @return whether or not this method matches statically
     */
    boolean matches(Method method, Class<?> targetClass);
    
}
  • 方法匹配,找到表達式範圍內匹配下的目標類和方法。在上文的案例中有所體現:methodMatcher.matches(method, targetObj.getClass())

實現切點表達式類

public class AspectJExpressionPointcut implements Pointcut, ClassFilter, MethodMatcher {

    private static final Set<PointcutPrimitive> SUPPORTED_PRIMITIVES = new HashSet<PointcutPrimitive>();

    static {
        SUPPORTED_PRIMITIVES.add(PointcutPrimitive.EXECUTION);
    }

    private final PointcutExpression pointcutExpression;

    public AspectJExpressionPointcut(String expression) {
        PointcutParser pointcutParser = PointcutParser.getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution(SUPPORTED_PRIMITIVES, this.getClass().getClassLoader());
        pointcutExpression = pointcutParser.parsePointcutExpression(expression);
    }

    @Override
    public boolean matches(Class<?> clazz) {
        return pointcutExpression.couldMatchJoinPointsInType(clazz);
    }

    @Override
    public boolean matches(Method method, Class<?> targetClass) {
        return pointcutExpression.matchesMethodExecution(method).alwaysMatches();
    }

    @Override
    public ClassFilter getClassFilter() {
        return this;
    }

    @Override
    public MethodMatcher getMethodMatcher() {
        return this;
    }

}
  • 切點表達式實現了 Pointcut、ClassFilter、MethodMatcher,三個接口定義方法,同時這個類主要是對 aspectj 包提供的表達式校驗方法使用。
  • 匹配 matches:pointcutExpression.couldMatchJoinPointsInType(clazz)pointcutExpression.matchesMethodExecution(method).alwaysMatches(),這部份內容能夠單獨測試驗證。

匹配驗證

@Test
public void test_aop() throws NoSuchMethodException {
    AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut("execution(* cn.bugstack.springframework.test.bean.UserService.*(..))");
    Class<UserService> clazz = UserService.class;
    Method method = clazz.getDeclaredMethod("queryUserInfo");   

    System.out.println(pointcut.matches(clazz));
    System.out.println(pointcut.matches(method, clazz));          
    
    // true、true
}
  • 這裏單獨提供出來一個匹配方法的驗證測試,能夠看看你攔截的方法與對應的對象是否匹配。

4. 包裝切面通知信息

cn.bugstack.springframework.aop.AdvisedSupport

public class AdvisedSupport {

    // 被代理的目標對象
    private TargetSource targetSource;
    // 方法攔截器
    private MethodInterceptor methodInterceptor;
    // 方法匹配器(檢查目標方法是否符合通知條件)
    private MethodMatcher methodMatcher;
    
    // ...get/set
}
  • AdvisedSupport,主要是用於把代理、攔截、匹配的各項屬性包裝到一個類中,方便在 Proxy 實現類進行使用。這和你的業務開發中包裝入參是一個道理
  • TargetSource,是一個目標對象,在目標對象類中提供 Object 入參屬性,以及獲取目標類 TargetClass 信息。
  • MethodInterceptor,是一個具體攔截方法實現類,由用戶本身實現 MethodInterceptor#invoke 方法,作具體的處理。像咱們本文的案例中是作方法監控處理
  • MethodMatcher,是一個匹配方法的操做,這個對象由 AspectJExpressionPointcut 提供服務。

5. 代理抽象實現(JDK&Cglib)

定義接口

cn.bugstack.springframework.aop.framework

public interface AopProxy {

    Object getProxy();

}
  • 定義一個標準接口,用於獲取代理類。由於具體實現代理的方式能夠有 JDK 方式,也能夠是 Cglib 方式,因此定義接口會更加方便管理實現類。

cn.bugstack.springframework.aop.framework.JdkDynamicAopProxy

public class JdkDynamicAopProxy implements AopProxy, InvocationHandler {

    private final AdvisedSupport advised;

    public JdkDynamicAopProxy(AdvisedSupport advised) {
        this.advised = advised;
    }

    @Override
    public Object getProxy() {
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), advised.getTargetSource().getTargetClass(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (advised.getMethodMatcher().matches(method, advised.getTargetSource().getTarget().getClass())) {
            MethodInterceptor methodInterceptor = advised.getMethodInterceptor();
            return methodInterceptor.invoke(new ReflectiveMethodInvocation(advised.getTargetSource().getTarget(), method, args));
        }
        return method.invoke(advised.getTargetSource().getTarget(), args);
    }

}
  • 基於 JDK 實現的代理類,須要實現接口 AopProxy、InvocationHandler,這樣就能夠把代理對象 getProxy 和反射調用方法 invoke 分開處理了。
  • getProxy 方法中的是代理一個對象的操做,須要提供入參 ClassLoader、AdvisedSupport、和當前這個類 this,由於這個類提供了 invoke 方法。
  • invoke 方法中主要處理匹配的方法後,使用用戶本身提供的方法攔截實現,作反射調用 methodInterceptor.invoke 。
  • 這裏還有一個 ReflectiveMethodInvocation,其餘它就是一個入參的包裝信息,提供了入參對象:目標對象、方法、入參。

cn.bugstack.springframework.aop.framework.Cglib2AopProxy

public class Cglib2AopProxy implements AopProxy {

    private final AdvisedSupport advised;

    public Cglib2AopProxy(AdvisedSupport advised) {
        this.advised = advised;
    }

    @Override
    public Object getProxy() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(advised.getTargetSource().getTarget().getClass());
        enhancer.setInterfaces(advised.getTargetSource().getTargetClass());
        enhancer.setCallback(new DynamicAdvisedInterceptor(advised));
        return enhancer.create();
    }

    private static class DynamicAdvisedInterceptor implements MethodInterceptor {

        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            CglibMethodInvocation methodInvocation = new CglibMethodInvocation(advised.getTargetSource().getTarget(), method, objects, methodProxy);
            if (advised.getMethodMatcher().matches(method, advised.getTargetSource().getTarget().getClass())) {
                return advised.getMethodInterceptor().invoke(methodInvocation);
            }
            return methodInvocation.proceed();
        }
    }

    private static class CglibMethodInvocation extends ReflectiveMethodInvocation {

        @Override
        public Object proceed() throws Throwable {
            return this.methodProxy.invoke(this.target, this.arguments);
        }

    }

}
  • 基於 Cglib 使用 Enhancer 代理的類能夠在運行期間爲接口使用底層 ASM 字節碼加強技術處理對象的代理對象生成,所以被代理類不須要實現任何接口。
  • 關於擴展進去的用戶攔截方法,主要是在 Enhancer#setCallback 中處理,用戶本身的新增的攔截處理。這裏能夠看到 DynamicAdvisedInterceptor#intercept 匹配方法後作了相應的反射操做。

5、測試

1. 事先準備

public class UserService implements IUserService {

    public String queryUserInfo() {
        try {
            Thread.sleep(new Random(1).nextInt(100));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "小傅哥,100001,深圳";
    }

    public String register(String userName) {
        try {
            Thread.sleep(new Random(1).nextInt(100));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "註冊用戶:" + userName + " success!";
    }

}
  • 在 UserService 中提供了2個不一樣方法,另外你還能夠增長新的類來加入測試。後面咱們的測試過程,會給這個兩個方法添加咱們的攔截處理,打印方法執行耗時。

2. 自定義攔截方法

public class UserServiceInterceptor implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        long start = System.currentTimeMillis();
        try {
            return invocation.proceed();
        } finally {
            System.out.println("監控 - Begin By AOP");
            System.out.println("方法名稱:" + invocation.getMethod());
            System.out.println("方法耗時:" + (System.currentTimeMillis() - start) + "ms");
            System.out.println("監控 - End\r\n");
        }
    }

}
  • 用戶自定義的攔截方法須要實現 MethodInterceptor 接口的 invoke 方法,使用方式與 Spring AOP 很是類似,也是包裝 invocation.proceed() 放行,並在 finally 中添加監控信息。

3. 單元測試

@Test
public void test_dynamic() {
    // 目標對象
    IUserService userService = new UserService();     

    // 組裝代理信息
    AdvisedSupport advisedSupport = new AdvisedSupport();
    advisedSupport.setTargetSource(new TargetSource(userService));
    advisedSupport.setMethodInterceptor(new UserServiceInterceptor());
    advisedSupport.setMethodMatcher(new AspectJExpressionPointcut("execution(* cn.bugstack.springframework.test.bean.IUserService.*(..))"));
    
    // 代理對象(JdkDynamicAopProxy)
    IUserService proxy_jdk = (IUserService) new JdkDynamicAopProxy(advisedSupport).getProxy();
    // 測試調用
    System.out.println("測試結果:" + proxy_jdk.queryUserInfo());
    
    // 代理對象(Cglib2AopProxy)
    IUserService proxy_cglib = (IUserService) new Cglib2AopProxy(advisedSupport).getProxy();
    // 測試調用
    System.out.println("測試結果:" + proxy_cglib.register("花花"));
}
  • 整個案例測試了 AOP 在於 Spring 結合前的核心代碼,包括什麼是目標對象、怎麼組裝代理信息、如何調用代理對象。
  • AdvisedSupport,包裝了目標對象、用戶本身實現的攔截方法以及方法匹配表達式。
  • 以後就是分別調用 JdkDynamicAopProxy、Cglib2AopProxy,兩個不一樣方式實現的代理類,看看是否能夠成功攔截方法

測試結果

監控 - Begin By AOP
方法名稱:public abstract java.lang.String cn.bugstack.springframework.test.bean.IUserService.queryUserInfo()
方法耗時:86ms
監控 - End

測試結果:小傅哥,100001,深圳
監控 - Begin By AOP
方法名稱:public java.lang.String cn.bugstack.springframework.test.bean.UserService.register(java.lang.String)
方法耗時:97ms
監控 - End

測試結果:註冊用戶:花花 success!

Process finished with exit code 0
  • 如 AOP 功能定義同樣,咱們能夠經過這樣的代理方式、方法匹配和攔截後,在對應的目標方法下,作了攔截操做進行監控信息打印。

6、總結

  • 從本文對 Proxy#newProxyInstance、MethodInterceptor#invoke,的使用驗證切面核心原理以及再把功能拆解到 Spring 框架實現中,能夠看到一個貌似複雜的技術其實核心內容每每沒有太多,但由於須要爲了知足後續更多的擴展就須要進行職責解耦和包裝,經過這樣設計模式的使用,以此讓調用方能更加簡化,自身也能夠不斷按需擴展。
  • AOP 的功能實現目前尚未與 Spring 結合,只是對切面技術的一個具體實現,你能夠先學習到如何處理代理對象、過濾方法、攔截方法,以及使用 Cglib 和 JDK 代理的區別,其實這與的技術不僅是在 Spring 框架中有所體現,在其餘各種須要減小人工硬編碼的場景下,都會用到。好比RPC、Mybatis、MQ、分佈式任務
  • 一些核心技術的使用上,都是具備很強的關聯性的,它們也不是孤立存在的。而這個能把整個技術棧串聯起來的過程,須要你來大量的學習、積累、由點到面的鋪設,才能在一個知識點的學習拓展到一個知識面和知識體系的建設。

7、系列推薦

相關文章
相關標籤/搜索