005-aop

实现 ProxyResolver

bytebuddy 实现动态代理

传统的 JDK 形式的动态代理,由于底层使用到了反射,而反射的效率比较低,而且 Java 仅仅只支持对接口代理,无法实现对具体类的代理。所以就需要另一种动态代理的技术来代替,我们这里使用 ByteBuddy 生成代理类。生成代理的代码是一个固定的模式,故我直接给出代码即可。

    public <T> T createProxy(T originBean, InvocationHandler handler) {
        // 目标Bean的Class类型:
        Class<?> targetClass = originBean.getClass();
        // 动态创建Proxy的Class:
        Class<?> proxyClass = this.byteBuddy
                // 子类用默认无参数构造方法:
                .subclass(targetClass, ConstructorStrategy.Default.DEFAULT_CONSTRUCTOR)
                // 拦截所有public方法:
                .method(ElementMatchers.isPublic()).intercept(InvocationHandlerAdapter.of(
                        // 新的拦截器实例:
                        (proxy, method, args) -> {
                            // 将方法调用代理至原始Bean:
                            return handler.invoke(originBean, method, args);
                        }))
                // 生成字节码:
                .make()
                // 加载字节码:
                .load(targetClass.getClassLoader()).getLoaded();
        // 创建Proxy实例:
        Object proxy;
        try {
            proxy = proxyClass.getConstructor().newInstance();
//            System.out.println("======================proxy: " + proxy);
        } catch (RuntimeException e) {
            log.error("RuntimeException: {}", e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("Exception: {}", e.getMessage());
            throw new RuntimeException(e);
        }
        return (T) proxy;
    }

实现 Around

生成了代理类后如何让代理生效呢?在 ioc 的开发中,我们曾经设计了一个接口 BeanPostProcessor 专门用于 Bean 的替换。所以,我们需要实现 BeanPostProcessor 来实现代理类的替换。

不论是什么注解,其实实现过程都十分相似,即,先从注解的 value 中获取 handler 的值,然后通过 handler 对当前 Bean 生成代理类,并进行替换。

并且,考虑到未来可能不止三种注解,所以,架构必须能够支持注解的拓展,也就是说,我们需要动态获取注解的类型,而不是写死(只判断是不是 After、Before、Around)。

所以,我们设计了 AnnotationProxyBeanPostProcessor<A extends Annotation> 类,这样,可以便于拓展注解,也可以减少代码的冗余。例如,我们想要日后想要拓展 @Transactional,只需要继承该类就可以实现了:

public class TransactionBeanPostProcessor extends AnnotationProxyBeanPostProcessor<Transactional> {
}

@Around

我们需要对代理的行为进行定义,也就是写 Handler,所以,在开发中,我们还需要用户自定义 Handler。

也就是定义一个实现了 InvocationHandler 接口的类,并实现 invoke 方法。

@Before

接下来的两个注解其实是 Around 的子集。Before 必须在方法 invoke 之前调用,而 After 必须要方法 invoke 之后调用。模式是固定的,所以模板方法就非常适合这个情况。

public abstract class BeforeInvocationHandlerAdapter implements InvocationHandler {
    public abstract void before(Object proxy, Method method, Object[] args);

    @Override
    public final Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before(proxy, method, args);
        return method.invoke(proxy, args);
    }
}

而用户只需要实现 before 方法就可以定义 Before 的行为了。我们可以直接使用 Around 注解来声明 Before 的逻辑,只不过 Handler 需要继承我们定义的而已。

不过,我们更具有区分度,我们还是设计了 @Before 注解,至于实现,非常简单,直接继承 AnnotationProxyBeanPostProcessor<A extends Annotation> 即可。

@After

与 Before 的实现逻辑完全相同,这里给出模板方法。

public abstract class AfterInvocationHandlerAdapter implements InvocationHandler {
    public abstract Object after(Object proxy, Object returnValue, Method method, Object[] args);

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

Optional

请注意,方法的调用完成是指完成 invoke 后就立即调用该方法。也就是说,当你需要观察返回值的时候,After 调用会必返回值更先一步。

例如,有类 originBean,和我们重写的 Handler:

@Component
@After("afterHandler")
//@Before("beforeHandler")
public class OriginBean {
    public String name;

    public String hello() {
        System.out.println("Hello, " + name + ".");
        return "Hello, " + name + ".";
    }

    public String morning() {
        return "Morning, " + name + ".";
    }
}
-----------------------------------------------------------
@Component
@Slf4j
public class AfterHandler extends AfterInvocationHandlerAdapter {
    @Override
    public Object after(Object proxy, Object returnValue, Method method, Object[] args) {
        log.info("AfterHandler: after method: {}", method.getName());
        log.info("proxy: {}", proxy);
        log.info("res: {}", returnValue);
        return returnValue;
    }
}

最后的显示为:

Hello, null.
2023-12-20 22:25:24.727 INFO  [main]  c.y.a.a.AfterHandler AfterHandler: after method: hello
2023-12-20 22:25:24.731 INFO  [main]  c.y.a.a.AfterHandler proxy: com.yelanyanyu.aop.after.OriginBean@5a5338df
2023-12-20 22:25:24.731 INFO  [main]  c.y.a.a.AfterHandler res: Hello, null.