自己實作AOP 2.0:實作Spring 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/
聲明:
1.原創博文,歡迎轉載、引用;轉載、引用請注明作者并附上原文連結,否則保留追究法律責任的權利。
2.本博文中引用他人的博文内容時均已注明出處,如有侵權,請聯系作者删除。
3.博文内容如有錯誤、不妥之處,歡迎留言指正,還請不吝賜教 =^_^=