JAVA實現簡單的切面註解

背景

今天在分析同事遇到一個springboot的註解和方法鎖一起用而導致的問題(@Transaction和synchronized用在同一個方法中由於事務先於鎖進入後於鎖釋放而可能引發的數據問題)中而突然思考到spring的Aspect是怎麼樣的執行順序,本文介紹java中其中一種(InvocationHandler)利用動態代理的方式實現的代理的方法,從而類似的機制我們推測出spring的切面其實也是在代理類中執行了切面的函數並在invoke之前或者之後去執行定義的點,而之所以能夠自動掃描切面應該是類似spring rabbitmq的實現掃面一遍所有的component bean獲取所有的註解然後執行,後續再仔細分析Aspect的實現,本文我們嘗試實現aspect註解從而實現捕獲函數執行前參數和執行後結果並打印出來

代碼

package com.oujiangping.leetcode;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface aspect {
}
package com.oujiangping.leetcode;

@aspect
public interface TestAspect {
    public String test(String sr);
}

package com.oujiangping.leetcode;

@aspect
public class TestAspectImpl implements TestAspect {
    @Override
    public String test(String sr) {
        System.out.println("run TestAspectImpl.test " + sr);
        return sr;
    }
}

package com.oujiangping.leetcode;

@aspect
public class TestAspectImplA implements TestAspect {
    @Override
    public String test(String sr) {
        System.out.println("run TestAspectImplA.test " + sr);
        return sr;
    }
}

package com.oujiangping.leetcode;
package com.oujiangping.leetcode;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class MyAspect implements InvocationHandler {
    Object instance;

    public Object aspect(Object instance) {
        this.instance = instance;
        return Proxy.newProxyInstance(instance.getClass().getClassLoader(), instance.getClass().getInterfaces(),this);
    }

    public void befor(Method method, Object[] args) {
        System.out.println("~~~~ befor: " + method.getName() + " " + args);
    }

    public void after(Object object) {
        System.out.println("~~~~ after: " + object);
    }

    public static void init() {
        Field[] fields= MyAspect.class.getDeclaredFields();

        for(int i=0;i<fields.length;i++){
            MyAspect myAspect = new MyAspect();
            aspect aspects = fields[i].getType().getAnnotation(aspect.class);
            if(aspects != null) {
                fields[i].setAccessible(true);
                try {
                    fields[i].set(myAspect, new MyAspect().aspect(fields[i].get(myAspect)));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result=null;
        befor(method, args);
        result = method.invoke(instance, args);
        after(result);
        return null;
    }

    public static TestAspect testAspect = new TestAspectImpl();
    public static TestAspect testAspectA = new TestAspectImplA();;

    public static void main(String []args) {
        init();
        testAspect.test("I'm TestAspectImpl");
        testAspectA.test("I'm TestAspectImplA");
    }
}


結果:
~~~~ befor: test [Ljava.lang.Object;@49476842
run TestAspectImpl.test I'm TestAspectImpl
~~~~ after: I'm TestAspectImpl
~~~~ befor: test [Ljava.lang.Object;@78308db1
run TestAspectImplA.test I'm TestAspectImplA
~~~~ after: I'm TestAspectImplA

總結

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章