自己实现SpringAOP,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()); } } } }
【该文章为本人原创,内容如有错误、不妥之处,还请不吝赐教 ^_^】