自己实现SpringAOP,含AOP实现的步骤分解
2019-08-16 10:07:57来源:博客园 阅读 ()
自己实现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()); } } } }
原文链接:https://www.cnblogs.com/laipimei/p/11163377.html
如有疑问请与原作者联系
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
- DES/3DES/AES 三种对称加密算法实现 2020-06-11
- 构建自己的jar包上传至Mvaen中央仓库和版本更新 2020-06-11
- SpringBoot + Vue + ElementUI 实现后台管理系统模板 -- 后 2020-06-10
- Spring Boot 实现定时任务的 4 种方式 2020-06-10
- JSP+SSH+Mysql+DBCP实现的租车系统 2020-06-09
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash