zoukankan      html  css  js  c++  java
  • 自己实现SpringAOP,含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());
                }
            }
        }
    }
    作者:赖皮梅
    声明:
    1.原创博文,欢迎转载、引用;转载、引用请注明作者并附上原文链接,否则保留追究法律责任的权利。
    2.本博文中引用他人的博文内容时均已注明出处,如有侵权,请联系作者删除。
    3.博文内容如有错误、不妥之处,欢迎留言指正,还请不吝赐教 =^_^=
  • 相关阅读:
    G. Reducing Delivery Cost 思维+最短路
    Bounding Wall 线段树 + 思维 ccpc 2020 秦皇岛 B
    Java代理模式
    Java开发 使用反射判断一个类的是否继承指定接口类
    Java开发 AES加解密工具类——兼容Android9.0
    Java byte转换工具类
    注册LiveData或者MutableLiveData的观察者导致的内存泄露问题
    Android开发 NavOptions记录
    关于MySQL的命名规范
    Locust学习笔记(5)
  • 原文地址:https://www.cnblogs.com/laipimei/p/11163377.html
Copyright © 2011-2022 走看看