1. 程式人生 > >模仿spring-aop的功能,利用註解搭建自己的框架。

模仿spring-aop的功能,利用註解搭建自己的框架。

屬性 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的功能,利用註解搭建自己的框架。