一、需求:
自己實現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()); } } } }