Spring:六、ProxyFactory使用

Spring:六、ProxyFactory使用

1 前言

Spring提供了编程式AOP代理方式,而不依赖于Spring Ioc,即ProxyFactory。使用此种方式可以很方便的使用JDK动态代理或CGLIB代理,且支持Advisor chain的使用,可以通过advisor链,增强需要代理的对象方法。

文档描述:

It is easy to create AOP proxies programmatically with Spring. 
This lets you use Spring AOP without dependency on Spring IoC.

The interfaces implemented by the target object are automatically proxied. 
The following listing shows creation of a proxy for a target object, 
with one interceptor and one advisor:

实例代码:

ProxyFactory factory = new ProxyFactory(myBusinessInterfaceImpl);
factory.addAdvice(myMethodInterceptor);
factory.addAdvisor(myAdvisor);
MyBusinessInterface tb = (MyBusinessInterface) factory.getProxy();

Spring文档参考:

https://docs.spring.io/spring-framework/docs/5.3.27/reference/html/core.html#aop-prog

2 使用

接口定义:

interface Fruit {
    void eat(String name);

    static void sale() {
        System.out.println("静态sale方法");
    }

    default void buy() {
        System.out.println("默认buy方法");
    }
}

实现类:

class Grape implements Fruit {

    @Override
    public void eat(String name) {
        System.out.println("eat:" + name);
    }

}

Spring底层源码可知,调用ProxyFactory的getProxy()方法,不论是cglib的实现ObjenesisCglibAopProxy,还是JDK代理的JdkDynamicAopProxy实现,MethodInvocation的实现都是使用ReflectiveMethodInvocation或其子类(子类也是调用super.proceed())。且它们实现都会调用ProxyFactory的父类AdvisedSupport的getInterceptorsAndDynamicInterceptionAdvice方法,用于获取advice的执行Chain。其中会使用DefaultAdvisorAdapterRegistry来调用getInterceptors方法注册所有的interceptors,而这个Registry类的适配器adaptors有3个,用于注册Spring自身提供的一些advice,即MethodBeforeAdviceAdapter,AfterReturningAdviceAdapter,ThrowsAdviceAdapter,只要它们的supportsAdvice方法返回true,则该adive也会被添加到执行的chain中,即advice是MethodBeforeAdvice,AfterReturningAdvice,ThrowsAdvice的子类实现即可。

由此我们可以自定义如下的增强逻辑:

前置增强:

class BeforeAdi implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("前置执行...");
    }
}

返回值后增强:

class AfterReturnAdi implements AfterReturningAdvice {
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("返回值后, 执行...");
    }
}

而ThrowsAdvice的调用较为特殊,即必须含有public方法afterThrowing,参数这里取1个,因为只要是Throwable的子类实现即可,所以这里可以自定义业务异常,用于处理发生自定义业务异常的场景:

自定义业务异常:

class MyError extends RuntimeException{
    public MyError() {
    }

    public MyError(String message) {
        super(message);
    }

    public MyError(String message, Throwable cause) {
        super(message, cause);
    }

    public MyError(Throwable cause) {
        super(cause);
    }

    public MyError(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}

异常增强(ThrowsAdvice会先执行增强逻辑,并且抛出异常):

public class ThrowErrorHandler implements ThrowsAdvice {
    // 因为底层源码使用getMethods,故而此 afterThrowing方法必须是throwsAdvice的public方法
    // 另外源码反射执行该方法,没有对该method:afterThrowing调用setAccessible,故而非public class也会反射调用失败
    // 故而该类最好不要写在同1个java文件中,即不要是非public class
    public void afterThrowing(MyError myError){
        System.out.println("发生未知自定义异常:" + myError.getMessage());
    }
}

源码实现即ThrowsAdviceInterceptor,因为适配器ThrowsAdviceAdapter的getInterceptor方法,就是直接返回new ThrowsAdviceInterceptor(advisor.getAdvice())拦截器。源码中的invoke逻辑:

@Nullable
public Object invoke(MethodInvocation mi) throws Throwable {
    try {
        return mi.proceed();
    } catch (Throwable var4) {
        Method handlerMethod = this.getExceptionHandler(var4);
        if (handlerMethod != null) {
            this.invokeHandlerMethod(mi, var4, handlerMethod);
        }

        throw var4;
    }
}

可知即递归调用ReflectiveMethodInvocation的proceed方法(MethodBeforeAdviceAdapter,AfterReturningAdviceAdapter亦是如此),如果抛出Throwable,则从预先的exceptionHandlerMap中取出对应的Throwable的Class的value,即Method。而这个Class,就是我们自定义的afterThrowing方法的Throwable参数的class,故而支持自定义业务异常的拦截增强。

因为该Method在this.invokeHandlerMethod(mi, var4, handlerMethod)方法中,是直接使用method.invoke执行该方法,此前Spring并未执行setAccessible的操作,也未执行过Spring-core包下的ReflectionUtils.makeAccessible(Method method)方法,故而此afterThrowing方法必须是public方法,且类本身的作用范围同样影响到Method方法的反射执行(Reflection下执行ensureMemberAccess,verifyMemberAccess方法返回false的场景,均会抛出IllegalAccessException),故而此类定义为public类为优,同时便于拓展。

亦或可以使用以下方式,自定义继承ThrowsAdvice的接口,然后自行实现该接口,因为接口方法默认是public,且重写方法时,作用域无法小于原重写方法的作用域,即不能为protected、private等,只能以public重写,只是重写时,若接口方法是Object,重写方法的返回值可以是其子类,即存在继承关系的类的重写,故而这里返回Boolean值。当然实际源码也未使用返回值,只是执行afterThrowing方法后,抛出异常而已:

public class ThrowErrorHandler implements ThrowsAdviceHandle<MyError> {
    // 因为底层源码使用getMethods,故而此 afterThrowing方法必须是throwsAdvice的public方法
    // 另外源码反射执行该方法,没有对该method:afterThrowing调用setAccessible,故而非public class也会反射调用失败
    // 故而该类最好不要写在同1个java文件中,即不要是非public class
    @Override
    public Boolean afterThrowing(MyError myError) {
        System.out.println("发生未知自定义异常:" + myError.getMessage());
        return Boolean.TRUE;
    }
}

interface ThrowsAdviceHandle<T extends Throwable> extends ThrowsAdvice {
    Object afterThrowing(T myError);
}

除了上述3种特殊的advice,当然自定义的MethodInterceptor也会添加到advisor chain中:

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

class MyAdvice implements MethodInterceptor {
    @Nullable
    @Override
    public Object invoke(@Nonnull MethodInvocation invocation) throws Throwable {
        if (invocation instanceof ReflectiveMethodInvocation) {
            System.out.println("***************advice1");
            return 123;
        }
        throw new RuntimeException("未知异常");
    }
}
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

class MyAdvice2 implements MethodInterceptor {
    @Nullable
    @Override
    public Object invoke(@Nonnull MethodInvocation invocation) throws Throwable {
        if (invocation instanceof ReflectiveMethodInvocation) {
            System.out.println("***************advice2");
            return 456;
        }
        return null;
    }
}

定义了MethodInterceptor 后,可以使用ProxyFactory增强,使用代理后的对象调用增强的Fruit.class接口的实例方法或default方法,均可以获得增强:

ProxyFactory factory = new ProxyFactory();

factory.setInterfaces(Fruit.class);
factory.setTarget(new Grape());
//  Advice must not be null
factory.addAdvice(new BeforeAdi());
factory.addAdvice(new AfterReturnAdi());
factory.addAdvice(new ThrowErrorHandler());
factory.addAdvice(new MyAdvice());
factory.addAdvice(new MyAdvice2());

Fruit fruit = (Fruit) factory.getProxy();
fruit.eat("葡萄");
fruit.buy();

执行结果如下:

前置执行...
***************advice1
返回值后, 执行...
前置执行...
***************advice1
返回值后, 执行...

修改MyAdvice,使其反射调用实例方法:

class MyAdvice implements MethodInterceptor {
    @Nullable
    @Override
    public Object invoke(@Nonnull MethodInvocation invocation) throws Throwable {
        if (invocation instanceof ReflectiveMethodInvocation) {
            System.out.println("***************advice1");
            ReflectiveMethodInvocation reflectiveMethodInvocation = (ReflectiveMethodInvocation) invocation;
            Object target = reflectiveMethodInvocation.getThis();
            return invocation.getMethod().invoke(target, invocation.getArguments());
        }
        throw new RuntimeException("未知异常");
    }
}

再次执行:

前置执行...
***************advice1
eat:葡萄
返回值后, 执行...
前置执行...
***************advice1
默认buy方法
返回值后, 执行...

之所以factory.addAdvice,添加了MyAdvice和MyAdvice2,但只执行了MyAdvice,是因为MyAdvice直接反射调用了该实例方法,即invocation.getMethod().invoke(target, invocation.getArguments()),所以链式执行advice chain时,因为已经return了,所以后续的MyAdvice2不会再次执行(Spring源码可知,该Chain的执行,instanceof MethodInterceptor 的增强,或adapter.supportsAdvice(advice),是按照list的顺序执行的,即addAdvice的添加顺序,所以这里先添加的特殊的3种增强,避免被自定义的MethodInterceptor 直接return,导致这三个不生效),若希望所有的advice都执行完,改为调用invocation.proceed(),即递归执行ReflectiveMethodInvocation的proceed方法即可,这也是Spring代理增强的设计中,非常出彩的逻辑(责任链设计模式中,即采用递归链式方式执行)。

再次修改MyAdvice、MyAdvice2的增强执行:

class MyAdvice implements MethodInterceptor {
    @Nullable
    @Override
    public Object invoke(@Nonnull MethodInvocation invocation) throws Throwable {
        if (invocation instanceof ReflectiveMethodInvocation) {
            System.out.println("***************advice1");
            return invocation.proceed();
        }
        throw new RuntimeException("未知异常");
    }
}
class MyAdvice2 implements MethodInterceptor {
    @Nullable
    @Override
    public Object invoke(@Nonnull MethodInvocation invocation) throws Throwable {
        if (invocation instanceof ReflectiveMethodInvocation) {
            ReflectiveMethodInvocation reflectiveMethodInvocation = (ReflectiveMethodInvocation) invocation;
            System.out.println("***************advice2");
            return invocation.proceed();
        }
        return null;
    }
}

再次执行,结果如下,可见全部的advice均已执行,在这些advice增强通过invoke方法执行完后,源码中会调用return this.invokeJoinpoint();,即反射执行该实例方法:

前置执行...
***************advice1
***************advice2
eat:葡萄
返回值后, 执行...
前置执行...
***************advice1
***************advice2
默认buy方法
返回值后, 执行...

如下为部分源码示例,因为Spring源码底层在链式执行全部增强后,判断if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1),则会反射调用该被增强的实例方法,故而一般只需要自定义增强逻辑即可,无需再手动反射调用该实例方法并return(当然,举例来说,若原本接口的返回值为Object,而重写方法比如返回为其子类Integer,而该方法执行比较耗时,希望增强是返回CompletableFuture对象,能够获取增强后的CompletableFuture对象并收集所有对象异步执行,提升效率,那么此时可以添加自定义实现的MethodInterceptor,直接return 返回自定义对实例方法包装后的CompletableFuture对象即可,也就不会执行invokeJoinpoint方法了,这也是Spring该编程式AOP实现方式非常方便的地方。另外异步执行通过代理实现的这个思想,也可以从Spring的@Async实现方式中参考,与该思想类似):

@Nullable
protected Object invokeJoinpoint() throws Throwable {
    return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
}

按照如上逻辑,再次修改eat方法实现:

class Grape implements Fruit {

    @Override
    public void eat(String name) {
        System.out.println("eat:" + name);
        throw new MyError("【默认方式异常】");
    }

}

再次执行,可见ThrowErrorHandler能够正确处理该异常(实际业务逻辑可以是失败DB插入错误日志、日志打印等等),自定义增强处理完后,则抛出异常:

前置执行...
***************advice1
***************advice2
eat:葡萄
发生未知自定义异常:【默认方式异常】
Exception in thread "main" action.MyError: 【默认方式异常】

最后,对于上述提到的返回值为Object的接口,使其返回值为其子类的实现,能够通过代理增强为CompletableFuture异步执行的对象方式,还可以通过自定义注解,配合SpringBoot的拓展BeanFactoryPostProcessor、BeanPostProcessor来实现对Bean的Field字段,自动代理为异步对象,由该异步代理对象,来达到方法异步执行的效果。降低耦合的同时,也不失为一种很好的编程思路。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值