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.