pc|别再if-else走天下了,整个注解多优雅( 三 )


-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true
该参数可以保存所生成的JDK动态代理类到本地 。 额外说一句 , 若我们想追踪cglib所生成的代理类 , 即对应的字节码文件 , 可以设置参数:
【pc|别再if-else走天下了,整个注解多优雅】System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "保存的路径")
添加参数后再次启动项目 , 可以看到我们项目里多了许多class文件(这里只截取了部分 , 笔者启动的项目共生成了97个动态代理类 。 由于我的项目是springboot环境 , 因此生成了许多如ConditionalOnMissingBean、Configuration、Autowired等注解对应的代理类):
pc|别再if-else走天下了,整个注解多优雅
本文插图
那接下来就是要找到我们所关心的 , 即jdk为我们自定义的OrderHandlerType注解所生成的代理类 。 由于jdk生成的动态代理类都会继承Proxy这个类 , 而java又是单继承的 , 所以 , 我们只需要找到实现了OrderHandlerType的类即可 。 遍历这些类文件 , 发现$Proxy63.class实现了我们定义的OrderHandlerType注解:
public final class $Proxy63 extends Proxy implements OrderHandlerType { private static Method m1 private static Method m2 private static Method m4 private static Method m3 private static Method m0 public $Proxy63(InvocationHandler var1) throws { super(var1) } // …省略}
我们知道 , jdk动态代理其实现的核心是:
也就是这个构造函数的InvocationHandler对象了 。 那么注解的InvocationHandler是哪个具体实现呢?不难发现就是:
这个类里面的核心属性 , 就是那个 memberValues , 我们在使用注解时给注解属性的赋值 , 都存储在这个map里了 。 而代理类中的各种方法的实现 , 实际上是调用了 AnnotationInvocationHandler 里的 invoke 方法 。 好了 , 现在我们知道了注解就是个接口 , 且通过动态代理实现其中所定义的各种方法 。 那么回到我们的OrderService , 为什么不把key的类型设置为OrderHandlerType?就像这样 。
private Map
orderHandleMap
如此一来 , 不管决定订单处理器orderhandler的因素怎么变 , 我们便可以以不变应万变(这不就是我们所追求的代码高扩展性和灵活性么) 。 那当我们的map的key变成了OrderHandlerType之后 , 注入和获取的逻辑就要相应改变 , 注入的地方很好改变 , 如下:
public class OrderService { private Map
orderHandleMap @Autowired public void setOrderHandleMap(List { // 注入各种类型的订单处理类 orderHandleMap = orderHandlers.stream().collect( Collectors.toMap(orderHandler -&gt AnnotationUtils.findAnnotation(orderHandler.getClass(), OrderHandlerType.class), v -&gt v, (v1, v2) -&gt v1)) } // ...省略}
orderHandlers)
那获取的逻辑要怎么实现?我们怎么根据order的来源和支付方式去orderHandleMap里获取对应的OrderHandler呢?问题变成了如何关联order的来源和支付方式与OrderHandlerType注解 。 还记得刚才所说的注解就是个接口吗 , 既然是个接口 , 我们自己实现一个类不就完事了么 , 这样就把order的来源和支付方式与OrderHandlerType注解关联起来了 。 说干就干 , 现在我们有了这么一个类 ,