欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

自己实现SpringAOP,AOP实现的步骤分解

程序员文章站 2024-02-05 22:01:58
自己实现AOP 2.0:实现Spring AOP,有环绕通知、前置通知、后置通知、返回通知、异常通知等。 ......

一、需求:

  自己实现aop 2.0:实现spring aop,有环绕通知、前置通知、后置通知、返回通知、异常通知等。
    已实现:①通过动态代理+通知的注解类,实现了前置通知、后置通知等各种通知;②切点(在需要通知的方法上加注解);③切面(同②);
    未实现:①通知的格式没写成可配置的; ②切点、切面没抽取成一个更方便配置的切面类;③其他。

  【自己实现aop 1.0版本(简易版):】

二、思路整理:

  1.涉及的角色:

    ①被代理类;

    ②被代理类要实现的接口;

    ③代理类;

    ④动态创建“代理类的对象”的类;

    ⑤注解类:

      a. 切面注解类,注解在类上:
        @aspect
      b. 各种通知注解,注解在方法上:
        @before
        @afterreturning
        @after
        @afterthrowing
        @around

    ⑥ioc容器:beanfactory(自己实现ioc容器:博客还没写完 * ~ *,写好了再附上链接)。

  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());
            }
        }
    }
}

 

【该文章为本人原创,内容如有错误、不妥之处,还请不吝赐教 ^_^】