• spring aop 动态代理批量调用方法实例


    今天项目经理发下任务,需要测试 20 个接口,看看推送和接收数据是否正常。因为对接传输的数据是 xml 格式的字符串,所以我拿现成的数据,先生成推送过去的数据并存储到文本,以便验证数据是否正确,这时候要批量调用这些同名方法,我觉得这里可以发展成有潜力的代码。

    推送比较好做数据,队友们都写好代码,但是有个问题,方法要的值都大致相同,封装的方式不一致,多人开发,有的封装对象里面,有的直接使用 Map.get(),唉,一千个人一千个哈姆雷特嘛,只好利用反射和动态代理节省自己的代码量,而且这种方式练练手,看上去屌屌的,我喜欢。

    对接是使用基于 webService 的 cxf 跟对方的 axis2 做 SOA 对接。 这两个框架兼容性上有问题,幸好同事已经解决了。 类对应的 url 已经封装好了,写在配置文件properties 中,以传输实体类bean 为键,对方的url 为键值对。

    思路
    • 要根据系统现有数据输出到文件,方便一个一个检查核对文档。
    • 它们都是实现同一接口。(Spring 实现一个及以上接口就会使用JDK动态代理,否则使用cglib)
    • 那可以判断是否实现同一个接口来拿 Service。
    • 要做这样的判断,要使用反射和动态代理调用方法。
    • 可以使用类名获取 Spring管理的类,那就可以字符串数组或集合来搞。
    • 取得代理类,强转为业务接口类再调用方法。
    • 调用方法需要形参,那就要的时候再造,而且数据大致一样,可以使用同一个成员变量。
    • 先去系统看看哪个批次数据比较充足的。
    • 声明这些公用数据。
    • 开始动手写。
    接口说明:
    • 接口都继承一个顶层接口 IBaseTradingCenter( TradingCenter = 交易中心)
    • 接口分为推送 IBaseTradingCenterClient,接收为 IBaseTradingCenterServer
    • 只有一个接口方法 synch
    • 接受两个参数 Object 和 Map<String, Object>
    • Object 是给传输Bean赋值的实体,Map 作为其他值的补充
    • 没有返回值
    • 抛出异常
    • 实现该接口的类全都处于Spring 管理
    做法是这样的:
    • 将这 20 个实现接口的的类的类名(例如: TenderReturnService.java),直接使用字符串数组存储,包含推送和接收(未区分,后面区分),使用字符串截取和首字符大小写处理一下。
    • 遍历数组,使用 Spring 的 WebApplicationContextUtils 获取传入字符串,获取 20 个 Service 的代理类 $Proxy0。
    • 使用 instanceof 判断代理类是否实现 IBaseTradingCenterClient(推送)接口,如果是,则用 IBaseTradingCenterClient 强制转型并存储到 List<IBaseTradingCenterClient> 中。
    • 大概获取到10个左右的推送类。(存储到List可以省略,但为代码可阅读还是不能省)
    • 遍历 List<IBaseTradingCenterClient> ,实际里面都是代理对象。
    • 需要判断代理对象的原始对象是否等同我们的业务类。
    • 查阅了一下资料,看了一下 AopUtils 源码,里面有几种方法可以使用,spring aop 有封装自己的代理模式。
    • AopUtils.isProxy() 判断是否是代理类、AopUtils.getTargetClass() 获取代理类目标对象(原始类)的 class 这两个方法我用得上。
    • AopUtils.getTargetClass() 获取原始类的 class,再跟业务类的 class 直接用 “==” 比较,为 true 原始类为该业务类。
    • 构造形参 Object 和 Map,传入代理类方法 $Proxy.synch(Object, Map)。
    • 在 Bean2XmlUtils 工具类中使用 FileUtils.writeString(str, data)写出文件。
    • 检查文件生成情况。
    • 完成。
    改进

    这里还有个问题需要解决:

    • 形参的问题,形参都是不一样的对象,但是使用的字段基本一样。
    • 这里我想到使用 BeanUtils 。但是这个工具类只是做对象与对象的拷贝。
    • 我可以这样想,反射得到对象的成员变量名称,用名称去一个 Map 中获取数值,如果能获取,则将 Map 中的值赋值给成员变量。那么就可以解决不同的形参对象的问题。
    • 声明一个 BeanUtils.setBeanForMap(Obj, Map)
  • 相关阅读:
    AddParent
    AddChild
    贝塞尔曲线代码
    顶点纹理shader
    抽象方法与抽象类
    Application类
    布局组件
    C#单例和Unity单例
    Unity&UGUI
    Json解析
  • 原文地址:https://www.cnblogs.com/zengyufei/p/5252069.html
Copyright © 2020-2023  润新知