天天看點

自己實作SpringAOP,含AOP實作的步驟分解

自己實作AOP 2.0:實作Spring AOP,有環繞通知、前置通知、後置通知、傳回通知、異常通知等。

一、需求:

  自己實作AOP 2.0:實作Spring AOP,有環繞通知、前置通知、後置通知、傳回通知、異常通知等。

    已實作:①通過動态代理+通知的注解類,實作了前置通知、後置通知等各種通知;②切點(在需要通知的方法上加注解);③切面(同②);

    未實作:①通知的格式沒寫成可配置的; ②切點、切面沒抽取成一個更友善配置的切面類;③其他。

  【自己實作AOP 1.0版本(簡易版):https://www.cnblogs.com/laipimei/p/11137250.html】

二、思路整理:

  1.涉及的角色:

    ①被代理類;

    ②被代理類要實作的接口;

    ③代理類;

    ④動态建立“代理類的對象”的類;

    ⑤注解類:

      a. 切面注解類,注解在類上:

        @Aspect

      b. 各種通知注解,注解在方法上:

        @Before

        @AfterReturning

        @After

        @AfterThrowing

        @Around

    ⑥IOC容器:BeanFactory(自己實作IOC容器:https://www.cnblogs.com/laipimei/p/11205510.html)。

  2.實作步驟:

    (1)被代理類、被代理類的接口、通知的注解類的建立;

    (2)建立一個“動态代理類”,并把“被代理類的執行個體”傳給該代理類;在該動态代理類的invoke()方法中,實作前置通知、後置通知等各種通知,也是在該invoke()方法中調用、執行真正的代理類要執行的那個方法。

    (3)建立一個可以動态建立“代理類的執行個體”的類,通過該類的getProxyInstance(Object obj)方法可以得到一個動态代理類的執行個體。

    (4)給方法加通知注解,該方法的執行個體須已交由IOC容器管理的;

    (5)周遊BeanFactory,找出方法上有@通知注解的bean,為這些bean生成代理類對象(步驟:MyProxy3.getProxyInstance(Object obj))

    (6)用代理類的執行個體去替代BeanFactory中的被代理類的執行個體

三、代碼實作:

被代理類的接口:

1 public interface SuperMan {
2     int add(int a, int b);
3     int divide(int a, int b);
4 }      

被代理類:

1 package MyIOCAndMyAop.bean;
 2 
 3 import MyIOCAndMyAop.Annotations.After;
 4 import MyIOCAndMyAop.Annotations.AfterReturning;
 5 import MyIOCAndMyAop.Annotations.AfterThrowing;
 6 import MyIOCAndMyAop.Annotations.Around;
 7 import MyIOCAndMyAop.Annotations.Aspect;
 8 import MyIOCAndMyAop.Annotations.Before;
 9 import MyIOCAndMyAop.Annotations.MyComponent;
10 
11 @Aspect//切面注解類,加了該注解就表示被注解的類的執行個體需要做動态代理。
12 @MyComponent//自定義注解類,有該注解就表示被注解類交由自定義IOC容器管理了。
13 public class Student implements SuperMan {
14     
15     @After
16     @AfterReturning
17     @Before
18     @AfterThrowing
19     @Override
20     public int add(int a, int b) {
21         System.out.println("--> a + b = " + (a + b));
22         return a + b;
23     }
24 
25     @Around
26     @Override
27     public int divide(int a, int b) {
28         return a/b;
29     }
30 }      

注解類:

1 package MyIOCAndMyAop.Annotations;
 2 
 3 import java.lang.annotation.ElementType;
 4 import java.lang.annotation.Retention;
 5 import java.lang.annotation.RetentionPolicy;
 6 import java.lang.annotation.Target;
 7 
 8 /**
 9  * 掃描BeanFactory,找出方法上有@Aspect注解的bean,為其建立代理類對象,并替代原bean。
10  */
11 @Target(ElementType.TYPE)
12 @Retention(RetentionPolicy.RUNTIME)
13 public @interface Aspect {
14 
15 }      
1 package MyIOCAndMyAop.Annotations;
 2 
 3 import java.lang.annotation.ElementType;
 4 import java.lang.annotation.Retention;
 5 import java.lang.annotation.RetentionPolicy;
 6 import java.lang.annotation.Target;
 7 
 8 /**
 9  * 前置通知13  */
14 @Target(ElementType.METHOD)
15 @Retention(RetentionPolicy.RUNTIME)
16 public @interface After {
17 
18 }      
1 package MyIOCAndMyAop.Annotations;
 2 
 3 import java.lang.annotation.ElementType;
 4 import java.lang.annotation.Retention;
 5 import java.lang.annotation.RetentionPolicy;
 6 import java.lang.annotation.Target;
 7 
 8 /**
 9  * 傳回通知(方法正常執行完,才執行的通知)
10  */
11 @Target(ElementType.METHOD)
12 @Retention(RetentionPolicy.RUNTIME)
13 public @interface AfterReturning {
14 
15 }      
package MyIOCAndMyAop.Annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 後置通知
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Before {

}      
package MyIOCAndMyAop.Annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 異常通知
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AfterThrowing {

}      
package MyIOCAndMyAop.Annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 環繞通知:around==>并不常用,但功能最強大。
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Around {

}      

動态代理類:

1 class MyInvocationHandler3 implements InvocationHandler {
  2     private Object object;// 被代理類
  3     private Object invoke;
  4 
  5     public void setObject(Object object) {
  6         this.object = object;
  7     }
  8 
  9     /**
 10      * 動态代理:實作了環繞通知、前置通知、後置通知等通知。
 11      */
 12     @Override
 13     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 14         // 入參的類型的處理,傳回被代理對象真正要執行的那個方法:
 15         Method declaredMethod = handleArgs(method);
 16 
 17         // 環繞通知:
 18         Boolean bool = false;
 19         if (null != declaredMethod.getAnnotation(MyIOCAndMyAop.Annotations.Around.class)) {
 20             bool = true;
 21         }
 22         aroundInform(declaredMethod, bool, method, args);
 23 
 24         // 前置通知、後置通知、傳回通知、異常通知等:
 25         try {
 26             if (null != declaredMethod.getAnnotation(MyIOCAndMyAop.Annotations.Before.class)) {
 27                 System.out.println(declaredMethod.getName() + " begings with : " + declaredMethod.getParameters());
 28             }
 29             
 30             //通過放射,真正執行被代理對象的方法:
 31             invoke = method.invoke(object, args);
 32             
 33             if (null != declaredMethod.getAnnotation(MyIOCAndMyAop.Annotations.AfterReturning.class)) {
 34                 System.out.println(declaredMethod.getName() + "  ends with : " + invoke);
 35             }
 36         } catch (Exception e) {
 37             if (null != declaredMethod.getAnnotation(MyIOCAndMyAop.Annotations.AfterThrowing.class)) {
 38                 System.out.println(declaredMethod.getName() + " occurs exception : " + e);
 39             }
 40         } finally {
 41             if (null != declaredMethod.getAnnotation(MyIOCAndMyAop.Annotations.After.class)) {
 42                 System.out.println(declaredMethod.getName() + " ends.");
 43             }
 44         }
 45         return invoke;
 46     }
 47 
 48     /**
 49      * 入參的類型的處理,這個方法很重要。
 50      *   55      * @return 被代理對象真正要執行的那個方法
 56      * @param method 被代理對象的接口中聲明的被代理方法
 57      * @throws NoSuchMethodException
 58      * @throws SecurityException
 59      */
 60     public Method handleArgs(Method method) throws NoSuchMethodException, SecurityException {
 61         Class<?>[] parameterTypes = method.getParameterTypes();
 62         switch (parameterTypes.length) {
 63         case 1:
 64             System.out.println("parameterTypes.length = 1 : " + parameterTypes[0]);
 65             return object.getClass().getDeclaredMethod(method.getName(), parameterTypes[0]);
 66         case 2:
 67             System.out.println("parameterTypes.length = 2 : " + parameterTypes[0] + " ; " + parameterTypes[1]);
 68             return object.getClass().getDeclaredMethod(method.getName(), parameterTypes[0], parameterTypes[1]);
 69         case 3:
 70             System.out.println("parameterTypes.length = 3 : " + parameterTypes[0] + " ; " + parameterTypes[1] + " ; "
 71                     + parameterTypes[2]);
 72             return object.getClass().getDeclaredMethod(method.getName(), parameterTypes[0], parameterTypes[1],
 73                     parameterTypes[2]);
 74         default:
 75             System.out.println("parameterTypes.length = 0 : " + parameterTypes.length);
 76             return object.getClass().getDeclaredMethod(method.getName());
 77         }
 78     }
 79 
 80     /**
 81      * 環繞通知
 82      * 
 83      * @param declaredMethod 被代理對象的被代理方法
 84      * @param bool
 85      * @param method         被代理對象的接口中聲明的被代理方法
 86      * @param args           被代理方法的聲明的入參
 87      */
 88     private void aroundInform(Method declaredMethod, Boolean bool, Method method, Object[] args) {
 89         if (bool) {
 90             try {
 91                 System.out.println(declaredMethod.getName() + " begings with : " + declaredMethod.getParameters());
 92                 invoke = method.invoke(object, args);
 93                 System.out.println(declaredMethod.getName() + "  ends with : " + invoke);
 94             } catch (Exception e) {
 95                 System.out.println(declaredMethod.getName() + " occurs exception : " + e);
 96             } finally {
 97                 System.out.println(declaredMethod.getName() + " ends.");
 98             }
 99         }
100     }
101 }      

動态建立“代理類的對象”的類:

class MyProxy3 {

    /**
     * 動态的建立一個代理類的對象.
     * 
     * MyProxy動态建立的“代理類的對象”: 
     *     class A implements Subject{ 
     *         private    Handler handler; 
     *         public void test() { 
     *             //獲得到目前方法名:
     *              handler.invoke(); 
     *         } 
     *     }
     */
    public static Object getProxyInstance(Object obj) {
        MyInvocationHandler3 handler = new MyInvocationHandler3();
        handler.setObject(obj);

        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), handler);
    }

    /**
     * 對于有@InOutLog注解的,用代理類的bean來替代BeanFactory中的被代理類的bean。
     * 這一步很重要,因為當執行到bean.method(),執行的就一定是bean對應的method()方法,
     * 如果此時沒有用代理類對象去替換,那麼執行的就是沒有InOutLog的原來的那個方法。
     */
    public static void updateBean(String completeClassName, Object object) {
        MyIOC.updateBeanFromBeanFactory(completeClassName, getProxyInstance(object));// (全類名,代理類的bean)
    }
}      

①掃描BeanFactory,找出方法上有@InOutLog注解的bean,為其建立代理類對象,并替代原bean。②使用測試:

public class MyAOP3 {
    public static void main(String[] args) {
        String completeClassName1 = "MyIOCAndMyAop.bean.Student";
        Object bean = MyIOC.getBean(completeClassName1);
        SuperMan superMan = (SuperMan) bean;
        superMan.add(2, 3);
        superMan.divide(10, 5);
    }
    
    static {
        init();
    }

    public static void init() {
        updateBeanFromBeanFactory();
    }

    /**
     * 掃描BeanFactory,找出方法上有@Aspect注解的bean,為其建立代理類對象,并替代原bean。
     */
    public static void updateBeanFromBeanFactory() {
        for (Map.Entry<String, Object> entry : MyIOC.getBeanFactory().entrySet()) {
            if (null != entry.getValue().getClass().getDeclaredAnnotation(Aspect.class)) {
                MyProxy3.updateBean(entry.getKey(), entry.getValue());
            }
        }
    }
}      

作者:賴皮梅

出處:https://www.cnblogs.com/laipimei/

聲明:

1.原創博文,歡迎轉載、引用;轉載、引用請注明作者并附上原文連結,否則保留追究法律責任的權利。

2.本博文中引用他人的博文内容時均已注明出處,如有侵權,請聯系作者删除。

3.博文内容如有錯誤、不妥之處,歡迎留言指正,還請不吝賜教 =^_^=