Aop implementation based on jdk dynamic proxy

Aop implementation based on jdk dynamic proxy

jdk's dynamic proxy is based on interfaces, there are certain limitations, must provide an interface for implementation

Getting started with jdk dynamic proxy

First, the proxy class must implement the InvocationHandler interface

When the delegated class calls a method, it is called through the method.invoke () statement in this method

From this we can implement a tool class like this

Note that although the parameters proxy and instance have the same method, if the first parameter of the invoke method cannot be passed into the proxy, it will cause a stack overflow.

The invoke method of the proxy class is called, which is an instance of InvocationHandler, so it is a recursive call, so the java.lang.StackOverflowError mentioned above will appear.

/**
 *
 * @param <T> 由于JDK动态代理的特性,需要一个实现接口,这里用于
 *           @see DynamicProxy#getProxyInstance() 的类型转换
 */
public class DynamicProxy<T> implements InvocationHandler {
 //由于JDK动态代理的特性,需要一个实现接口,这里用于类型转换
    private final Class<T> instanceInterfaceClass;
    //被代理的类
    private final Object instance;
    /**
     * 被代理的类调用方法时都通过这个方法内的method.invoke()语句调用
     * 注意虽然参数proxy和instance拥有相同的方法,但是如果invoke方法的第一个参数不能传入   
     * proxy,会导致堆栈溢出
     * @param proxy 当前代理类
     * @param method 当前方法
     * @param args 当前方法参数列表
     * @return 方法返回值
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object res = null;
        try {
            
            res = method.invoke(instance, args);
            
        } catch (IllegalAccessException e) {
           //处理异常
        }
        return rs;
    }

    /**
     * 获取代理类
     * @return 代理类
     */
    public T getProxyInstance(){
        Class<?> instanceClass = instance.getClass();
        return (T) Proxy.newProxyInstance(instanceClass.getClassLoader(), instanceClass.getInterfaces(), this);
    }

复制代码

Finally, get the proxy class by instantiating this class and calling the getProxyInstance method

Add a callback for a particular time node

Since the corresponding method we call adds a proxy, we can also add a callback before the method is called, after the call, after throwing an exception, and after returning

Before the method is called, we can generally use it for parameter verification or parameter modification, so we can establish a mapping like this

Object []-> Object [], that is, its callback function (interface is) Function <Object [], Object []>

After the call (before the return value), we can generally handle the return value and modify it, which means that we can establish such a mapping

Object-> Object, that is, its callback function (interface is) Function <Object, Object>

After the exception is thrown, we can consume exception information for the thrown exception, so we can establish such a mapping Exception-> void

That is, its callback function (the interface is) Consumer

After returning the value, you can record some information. In theory, you can also use the Consumer interface, but you need to create another entity class yourself.

, So I chose to make an interface myself

Of course, we cannot proxy all methods, so we can add a filter to control whether the method is enhanced, and establish

Method-> boolean mapping, namely Function <Method, Boolean>

/**
 * 返回值后的回调,包含被代理的实例,代理类,当前的方法,返回值,参数列表
 */
@FunctionalInterface
public interface AfterResultCallback{
    /**
     *
     * @param instance 被代理的实例
     * @param proxy 当前代理
     * @param method 被增强的方法
     * @param res 返回值
     * @param arg 参数
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    void callback(Object instance, Object proxy, Method method,Object res,Object... arg) throws InvocationTargetException, IllegalAccessException;
}
复制代码

So the callback tool class above can be rewritten as

/**
 *
 * @param <T> 由于JDK动态代理的特性,需要一个实现接口,这里用于
 *           @see DynamicProxy#getProxyInstance() 的类型转换
 */
public class DynamicProxy<T> implements InvocationHandler {
    //异常时的回调
    private Consumer<Exception> exceptionCallback;
    //方法调用时的回调,可以用于修改入参或者验证入参
    private Function<Object[],Object[]> beforeInvokeCallback;
    //在方法执行后返回值之前的回调,可以修改返回值(不能绕开类型检测)
    //也就说原函数返回T类型不能修改为返回R类型(T和R没有继承关系)
    private Function<Object,Object> beforeResultCallback;
    //返回值后的回调
    //Object instance, Object proxy, Method method,Object res,Object... arg)
    private AfterResultCallback afterResultCallback;
    //方法拦截的条件
    private Function<Method,Boolean> methodVerify;

    //由于JDK动态代理的特性,需要一个实现接口,这里用于类型转换
    private final Class<T> instanceInterfaceClass;
    //被代理的类
    private final Object instance;

    /**
     *
     * @param proxy 当前代理类
     * @param method 当前方法
     * @param args 当前方法参数列表
     * @return 方法返回值
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //如果没有拦截条件,或者不满足条件直接执行
        if (methodVerify == null || !methodVerify.apply(method)) {
            return method.invoke(instance, args);
        }
        Object res = null;
        try {
            //如果存在回调,那么调用
            if (beforeInvokeCallback != null) {
                args = beforeInvokeCallback.apply(args);
            }
            res = method.invoke(instance, args);
            if (beforeResultCallback != null){
                res = beforeResultCallback.apply(res);
            }
            if (afterResultCallback != null){
                afterResultCallback.callback(instance, proxy, method, res, args);
            }
        } catch (IllegalAccessException e) {
            if (exceptionCallback != null) {
                exceptionCallback.accept(e);
            }
        }
        return res;
    }

    /**
     * 获取代理类
     * @return 代理类
     */
    public T getProxyInstance(){
        Class<?> instanceClass = instance.getClass();
        return (T) Proxy.newProxyInstance(instanceClass.getClassLoader(), instanceClass.getInterfaces(), this);
    }

    /**
     *
     * @param instanceInterfaceClass 代理接口
     * @param instance 被代理的类
     */
    public DynamicProxy(Class<T> instanceInterfaceClass, Object instance) {
        this.instanceInterfaceClass = instanceInterfaceClass;
        this.instance = instance;
    }

    //以下均为注册回调函数,用builder模式构建
    public DynamicProxy<T> setExceptionCallback(Consumer<Exception> exceptionCallback) {
        this.exceptionCallback = exceptionCallback;
        return this;
    }

    public DynamicProxy<T> setBeforeInvokeCallback(Function<Object[], Object[]> beforeInvokeCallback) {
        this.beforeInvokeCallback = beforeInvokeCallback;
        return this;
    }

    public DynamicProxy<T> setBeforeResultCallback(Function<Object, Object> beforeResultCallback) {
        this.beforeResultCallback = beforeResultCallback;
        return this;
    }

    public DynamicProxy<T> setAfterResultCallback(AfterResultCallback afterResultCallback) {
        this.afterResultCallback = afterResultCallback;
        return this;
    }

    public DynamicProxy<T> setMethodVerify(Function<Method,Boolean> methodVerify) {
        this.methodVerify = methodVerify;
        return this;
    }
}

复制代码

Aop function realization

We have made the tool class of dynamic proxy, now we need to consider how to weave the enhanced method into the enhanced method

Aspect method annotation

Through annotations, we can mark the callback functions of each stage in the cut plane, and then map the corresponding method to our corresponding interface through reflection

That is, the marked function instance (method.invoke ()) is called in the implementation class of the corresponding interface

@AfterResult @BeforeInvoke @BeforeResult @ExceptionCallBack

Corresponding to the return value, before the original method is called, after the return value, after throwing an exception

All are empty annotations, only used for annotations, and do not carry data, so I will just give an example

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AfterResult {
}
复制代码
Filter method mode annotation

Simply write, only control the return value type and method name

Later can be expanded to detection method signature

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MethodPatten {
    //返回值类型
    Class[] res() default{Object.class};
    //方法名,为空则放行所有方法
    String[] methodName() default {""};
}

复制代码
Initialize the Aop component

All methods of scanning slices will mark annotations and methods to establish a relationship

 //切面方法
    private Object aspect;
    private Object instance;
    private Class<T> instanceInterface;
    //切面方法与对应注解的关系
    private Map<Class,Method> annotationToMethod;

    /**
     * @param aspect 切面类
     * @param instance 被代理实例
     */
    public AOP(Object aspect, Object instance) {
        this.aspect = aspect;
        this.instance = instance;
        this.annotationToMethod = new HashMap<>();
        Method[] methods = aspect.getClass().getMethods();
        //只获取第一个注解作为键,方法作为值
        for (Method method : methods) {
            Annotation[] annotations = method.getAnnotations();
            if (annotations.length > 0){
                //重复注解的只保留第一个扫描到的
                //必须使用annotationType(),如果使用getClass则是获取的代理类
                annotationToMethod.putIfAbsent(annotations[0].annotationType(),method);
            }
        }
    }

复制代码
Get an example of a method filtering interface
//获取拦截条件
    private Function<Method,Boolean> getMethodVerify(){
        //如果没有MethodPattern指定条件 则全不拦截
        MethodPatten patten = aspect.getClass().getAnnotation(MethodPatten.class);
        if (patten == null) {
            return (m) -> false;
        }

        return (m) -> {
            //验证被增强的方法(被代理的类)的返回值是否符合条件
            boolean isResPass = false;
            for (Class re : patten.res()) {
                if (re.equals(m.getReturnType())){
                    isResPass = true;
                    break;
                }
            }
            //验证被增强的方法(被代理的类)的方法名是否符合条件
            boolean isMethodNamePass =false;
            for (String s : patten.methodName()) {
                //条件注解中指定的方法名为空则直接放行
                if (s.isEmpty() || s.equals(m.getName())){
                    isMethodNamePass = true;
                    break;
                }
            }
            //全通过才放行
            return isMethodNamePass && isResPass;
        };
    }

复制代码
Get callback instance before function call
//对应织入方法必须为同参数列表长度,必须返回值一致
    private Function<Object[],Object[]> getBeforeInvokeCallback(){
        Function<Object[],Object[]> res = null;
        //获取对应方法,没有就跳过
        Method method = annotationToMethod.get(BeforeInvoke.class);
        if (method == null){
            return null;
        }

        res = (arg) -> {
            try {
                //强制防止展开
                //这个method是切面增强的方法,通过调用这个方法对arg处理
                return (Object[]) method.invoke(aspect,(Object)arg);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
            return null;
        };
        return res;
    }
   
复制代码
Get exception thrown callback instance
  private Consumer<Exception> getExceptionCallback(){
        Method method = annotationToMethod.get(ExceptionCallback.class);
        if (method == null){
            return null;
        }
        Consumer<Exception> res = (e) -> {
            try {
                method.invoke(aspect, e);
            } catch (IllegalAccessException illegalAccessException) {
                illegalAccessException.printStackTrace();
            } catch (InvocationTargetException invocationTargetException) {
                invocationTargetException.printStackTrace();
            }
        };
        return res;
    }
  
复制代码
Callback before getting the return value
 private Function<Object,Object> getBeforeResultCallback(){
        Method method = annotationToMethod.get(BeforeResult.class);
        if (method == null){
            return null;
        }
        Function function = (res) -> {
            try {
                return method.invoke(aspect, res);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
            return null;
        };
        return function;
    }
   
复制代码
Callback after getting the return value
   private AfterResultCallback getAfterResultCallback(){
        Method method = annotationToMethod.get(AfterResult.class);
        if (method == null){
            return null;
        }
        AfterResultCallback afterResultCallback = (proxied,proxy,proxyMethod,res,arg) ->{
            method.invoke(aspect, proxied,proxy,proxyMethod,res,arg);
        };
        return afterResultCallback;
    }

复制代码
Get proxy class
public T getInstance(){
        //利用工具类获取代理类并注册回调函数,返回值为代理类
        DynamicProxy<T> proxy = new DynamicProxy<>(instanceInterface, instance);
        proxy.setMethodVerify(getMethodVerify())
                .setBeforeInvokeCallback(getBeforeInvokeCallback())
                .setExceptionCallback(getExceptionCallback())
                .setBeforeResultCallback(getBeforeResultCallback())
                .setAfterResultCallback(getAfterResultCallback());
        return proxy.getProxyInstance();
    }
复制代码

Aop functional test

interface

public interface I {
    Object dosome(Integer integer1,Integer i2);
    default double add(Integer integer1,Integer integer2,Integer i3){
        return integer1+integer2+i3;
    }
}

复制代码

class

public class Impl implements I {
    @Override
    public Object dosome(Integer integer1,Integer integer2) {
        return (Object) Integer.max(integer1, integer2);
    }
}

复制代码

section

@MethodPatten(res = double.class)
public class aspect{
    @BeforeInvoke
    public Object[] beforeinvoke(Object...objects){
        System.out.println("参数列表为"+ Arrays.toString(objects));
        return objects;
    }
    @BeforeResult
    public Object before(Object o){
        System.out.println("修改为double max");
        return Double.MAX_VALUE;
    }
    @AfterResult
    public void after(Object instance, Object proxy, Method method, Object res, Object...arg){
        System.out.println("instance is "+instance.getClass());
        System.out.println("proxy is "+proxy.getClass());
        System.out.println("method is "+method.getName());
        System.out.println("return value is "+res);
        System.out.println("arg is "+Arrays.toString(arg));
    }
}

复制代码

testing method

public static void main(String[] args)throws InterruptedException {
        AOP<I> aop = new AOP<>(new aspect(), new Impl());
        I i = aop.getInstance();
        System.out.println(i.add(100, 10,2000));
        System.out.println("\n"+i.dosome(100, 312));
    }
复制代码

Console output

It can be seen that only the method of returning the double return value is intercepted

参数列表为[100, 10, 2000]
修改为double max
instance is class MySpring.Aop.Test.Impl
proxy is class com.sun.proxy.$Proxy6
method is add
return value is 1.7976931348623157E308
arg is [100, 10, 2000]
1.7976931348623157E308

312
复制代码

Guess you like

Origin juejin.im/post/5e917760f265da47eb059ebc