模仿spring-aop的功能,利用註解搭建自己的框架。
阿新 • • 發佈:2018-02-08
屬性 def name rac java8 out fault 一個 lte
入JAVA坑7月有余,也嘗試自己手動搭建框架,最近對spring aop的這種切面很著迷,為此記錄下自己目前搭出來的小小的demo,後續有時間也會繼續改進自己的demo。望大神們不吝賜教。
主要還是運用反射和java自帶的代理類。理論知識就不說了,因為我目前也不是很清楚,避免誤導,還是避而不談吧。好了,直接根據代碼擼吧。
結構:
接口
Person.java
public interface Person { void say(); }
接口實現類
Man.java
public class Man implements Person { @Override public void say() { System.out.println("男人say:...."); } }
自定義註解
@interface WaterAOP
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.PARAMETER, ElementType.METHOD}) @Documented public @interface WaterAOP { enum METHOD{before,after,afterthrowing} METHOD method() default METHOD.after; String Name() default "類全名"; }
自定義註解類
WaterLog.java
public class WaterLog { @WaterAOP(Name = "com.water.aop.attempt3.Man",method = WaterAOP.METHOD.after) public void afterAction(){ System.out.println("後置行為"); } @WaterAOP(Name = "com.water.aop.attempt3.Man",method = WaterAOP.METHOD.before) public void beforeAction(){ System.out.println("前置行為"); } }
實現自定義代理類(就是在
Proxy.newProxyInstance()方法的第三個參數裏做手腳。用了java8的lambda表達式。
)
ProxyFactory.java
public class ProxyFactory { // 維持一個實現接口的被代理的對象,後面改為對象組,由淺入深 private Person person; private WaterLog waterLog; private Method beforeMethod=null,afterMethod=null; public ProxyFactory(Person person,WaterLog waterLog){ this.person=person; this.waterLog=waterLog; } public Object getProxyInstance(){ return Proxy.newProxyInstance( person.getClass().getClassLoader(), person.getClass().getInterfaces(), // 第一個參數就是代理者,如果你想對代理者做一些操作可以使用這個參數; // 第二個就是被執行的方法, // 第三個是執行該方法所需的參數。 (Object proxyObj, Method method,Object[] args)->{ //如果沒有傳入aop 直接返回空 if(waterLog==null){ return null; } Class aop=waterLog.getClass(); Class c = person.getClass(); // 獲取aop類的方法的註解並賦給自定義的一些變量,下面根據這些變量是否有值來確定是否有註解 getAnnotation(aop,c); if(beforeMethod!=null){ beforeMethod.invoke(waterLog); } // 代理對象執行方法並且獲得返回值 Object returnValue=method.invoke(person,args); if(afterMethod!=null){ afterMethod.invoke(waterLog); } return returnValue; } ); } private void getAnnotation(Class aop,Class proxy){ //如果有AOP的類 if(waterLog!=null){ // 獲取切面類所有的方法 Method[] methodsAOP=aop.getMethods(); // 如果切入的日誌類的方法不為空 if(methodsAOP!=null){ for(Method logMethod:methodsAOP){ // 取得WaterLog類的方法上WaterAOP註解 WaterAOP waterAOP=logMethod.getAnnotation(WaterAOP.class); if(waterAOP!=null) { // 如果AOP上的註解與傳入的類名一致 if (proxy.toString().substring(6).equals(waterAOP.Name())) { if (waterAOP.method() == WaterAOP.METHOD.before) { // 賦值 ,後面再執行 beforeMethod=logMethod; }else if(waterAOP.method() == WaterAOP.METHOD.after){ afterMethod=logMethod; } } } } } } } }
zhuanzi https://www.cnblogs.com/water-zmh/p/8427877.html
測試類
Test.java (junit是個測試包,也可以直接用main方法)
public class Test { @org.junit.Test public void waterAOP(){ Person person=new Man(); Person proxyPerson=(Person) new ProxyFactory(person,new WaterLog()).getProxyInstance(); proxyPerson.say(); } }
大致的流程就是:傳入要被代理的類和自定義的註解類,運用反射獲取註解類裏方法上的註解屬性的值,然後進行比對,再進行相應的操作。
模仿spring-aop的功能,利用註解搭建自己的框架。