WebServcie结合Spring结合动态代理进行抽象封装以及性能优化

webService抽象客户端封装、动态代理提升使用性能

1. 什么是webService
  webService就是在web上提供非相关系统与系统之间进行数据交互的一种服务。通过实现定义好的wsdl借口配置文件,进行约定以及调用。
在企业的内部系统中很常见,尤其是比较大型的企业,有数十种内部使用的系统,之间的通信基本上都是使用webService。
通俗点说就是:你要调用别人的服务,你就通过wsdl生成客户端代码,方便进行直接调用。
你需要被别人调用,你就通过wsdl生成服务端代码,方便对方系统进行推送调用。
2. 如何实例化
  通过JaxWsProxyFactoryBean传入(wsdl地址、用户名、密码、接口类)就能够远端调用实例。
  获得实例调用方法,方法结束整个流程结束。
3. 如何封装以及提升性能
  一次获得实例后,设置远端参数,实现延长失效。创建动态代理的客户端实例,供系统调用。
4. 由于每次调用的接口可能不同,但是实际上面的流程都是通过wsdl地址、以及接口类,获取对应的实例。
  所以可进行封装,接口类名通过泛型的方式传入、而公开一个抽象类,其中一个抽象方法传入对应的wsdl地址。这样讲两个动态的参数传入,使用泛型的形式生成对应的客户端。

  设置客户端的链接参数,改变失效时间。通过实例创建动态代理,公开给别人调用。

思路:

1. 通过Spring框架中的FactoryBean对象传入对应的接口泛型,进行上层封装

2. 定义抽象类,声明抽象方法getWSServiceUrl获得每个客户端对应的实例地址。

3. @PostConstruct通过容器启动的时候加载对应的JaxWsProxyFactoryBean工厂对象

4. 创建客户端的时候修改客户端映射以及策略,允许分块传输、设置长连接时长

5. 创建客户端代理类,调用代理的时候才调用真正的客户端实例

实现:

  1 package helloworld;
  2
  3 import java.lang.reflect.InvocationHandler;
  4 import java.lang.reflect.Method;
  5 import java.lang.reflect.ParameterizedType;
  6 import java.lang.reflect.Proxy;
  7 import java.lang.reflect.Type;
  8
  9 import javax.annotation.PostConstruct;
 10
 11 import org.apache.commons.lang3.ArrayUtils;
 12 import org.apache.commons.lang3.StringUtils;
 13 import org.apache.cxf.endpoint.Client;
 14 import org.apache.cxf.frontend.ClientProxy;
 15 import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
 16 import org.apache.cxf.transport.http.HTTPConduit;
 17 import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
 18 import org.slf4j.Logger;
 19 import org.slf4j.LoggerFactory;
 20 import org.springframework.beans.factory.FactoryBean;
 21
 22 /**
 23  * 描述: 定义一个抽象类,实现工厂Bean方法,使用泛型来定义传入的接口类,未定义的接口类
 24  * 调用方法,使用getClient方法来调用对应的WebService
 25  */
 26 public abstract class AbstractCxfClient<T> implements FactoryBean<T> {
 27
 28     private static final Logger logger = LoggerFactory.getLogger(AbstractCxfClient.class); // 日志处理工具类
 29
 30     private JaxWsProxyFactoryBean factory; // apache webservice FactoryBean
 31
 32     private volatile T client; // 接口客户端泛型类
 33
 34     private Class<?> genericClazz; // Class<?>是通配泛型,?可以代表各种类型
 35
 36     /**
 37      * 方法说明:初始化webservice客户端方法 关于在spring 容器初始化 bean 和销毁前所做的操作定义方式有三种
 38      * 通过@PostConstruct 和@PreDestroy 方法 实现初始化和销毁bean之前进行的操作
 39      *
 40      * @throws Exception
 41      */
 42     @PostConstruct
 43     void initial() throws Exception { // 初始化操作
 44         String url = getWSServiceUrl(); // 服务的地址
 45         if (StringUtils.isBlank(url)) // 地址为空,报错
 46         {
 47             throw new Exception("webservice client 初始化失败。" + this.getClass().getName());
 48         }
 49         Type type = this.getClass().getGenericSuperclass(); // 获取当前类的父类,或者说就是抽象类
 50
 51         if (type instanceof ParameterizedType) { // 是否是具有泛型的抽象类
 52             ParameterizedType pt = (ParameterizedType) type;// 获取对应的存储泛型类的类
 53             Type[] typeArr = pt.getActualTypeArguments(); // 获取泛型类名称的字符串数组
 54             if (ArrayUtils.isEmpty(typeArr)) { // 如果为空,说明没有传入泛型
 55                 throw new RuntimeException("所要调用的服务端接口不能为空" + this.getClass().getName());
 56             }
 57             genericClazz = Class.class.cast(typeArr[0]); // 由于代码写明了只有一个泛型类名字
 58             factory = new JaxWsProxyFactoryBean(); // 创建工厂
 59             factory.setServiceClass(genericClazz); // 设置对应的服务的类名
 60             String userName = this.getUserName(); // 设置webServie用户名
 61             if (StringUtils.isNotBlank(userName)) {
 62                 factory.setUsername(userName);
 63             }
 64             String possword = this.getPossword(); // 设置webService密码
 65             if (StringUtils.isNoneBlank(possword)) {
 66                 factory.setPassword(possword);
 67             }
 68             client = null; // 重置客户端
 69             factory.setAddress(url); // 设置对应的url连接
 70         } else { // 报错无效的客户端实例
 71             throw new RuntimeException("无效的客户端实例" + this.getClass().getName());
 72         }
 73     }
 74
 75     /**
 76      * 方法说明:<br>
 77      * 获取发发送实例获取代理后的客户端实例
 78      *
 79      * @param client
 80      * @return 代理后的客户端实例
 81      */
 82     private void httpClientPolicy(T client) {
 83         Client proxy = null; // 端点客户端
 84         HTTPConduit conduit = null;
 85         HTTPClientPolicy policy = null;
 86         try {
 87             // 通过实例获取对应的客户端代理
 88             proxy = ClientProxy.getClient(client);
 89             conduit = (HTTPConduit) proxy.getConduit(); // 获取静态映射
 90             policy = new HTTPClientPolicy(); // 创建策略
 91             policy.setAllowChunking(false);  // 设置允许分块传输
 92             policy.setConnectionTimeout(60000);    // 连接服务器超时时间一分钟
 93             policy.setReceiveTimeout(60000);// 等待服务器响应超时时间一分钟
 94             conduit.setClient(policy); // 将策略设置进端点
 95         } catch (Throwable t) {
 96             throw new RuntimeException(t.getMessage());
 97         }
 98     }
 99
100     /**
101      * 2016年3月21日 601008方法说明: CXF客户端一次获取,多次使用,方法调用异常,重新获取客户客户端
102      *
103      * @return T CXF客户端实例
104      */
105     @SuppressWarnings("unchecked")
106     public T getClient() {
107         // 如果不存在对应的客户端,才进行客户端远端获取,如果存在的话,就直接使用
108         if (null == client) {
109             synchronized (this) {
110                 if (null == client) {
111                     try {
112                         // 获取客户端
113                         client = (T) factory.create();
114                         // 设置真实客户端时长
115                         httpClientPolicy(client);
116                         // 创建客户端动态代理(调用方法通过代理调用)
117                         client = (T) (new CxfInvocationHandler(client)).getProxy();
118                     } catch (Throwable t) {
119                         client = null;
120                         throw t;
121                     }
122                 }
123             }
124         }
125         return client;
126     }
127
128     @Override
129     public T getObject() throws Exception {
130         return getClient();
131     }
132
133     @Override
134     public Class<?> getObjectType() {
135         return genericClazz;
136     }
137
138     @Override
139     public boolean isSingleton() {
140         // 使用单例模式
141         return true;
142     }
143
144     /**
145      * 2016年3月12日 wulonghuai方法说明:
146      *
147      * @return String webservice wsdl路径 客户端必须实现这个方法
148      */
149     public abstract String getWSServiceUrl();
150
151     public String getUserName() { // 暂时调用的webService都是不用用户名以及用户密码的,所以暂时返回空
152         return null;
153     }
154
155     public String getPossword() { // 暂时调用的webService都是不用用户名以及用户密码的,所以暂时返回空
156         return null;
157     }
158
159     // CXF代理对象的实现类
160     private class CxfInvocationHandler implements InvocationHandler {
161
162         // 目标对象
163         private Object target;
164
165         /**
166          * 构造方法
167          *
168          * @param target
169          *        目标对象
170          */
171         public CxfInvocationHandler(Object target) {
172             super();
173             this.target = target;
174         }
175
176         /**
177          * 执行目标对象的方法
178          */
179         public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
180             try {
181                 return method.invoke(target, args);
182             } catch (Throwable t) {
183                 // 动态代理调用对方的方法
184                 client = null;// 服务调用异常,客户端置空,方便后面重新获取客户端
185                 throw t;
186             }
187         }
188
189         public Object getProxy() {
190             // 传入接口、传入类加载器、传入当前对象
191             return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
192                     target.getClass().getInterfaces(), this);
193         }
194     }
195 }

参考资料:

  cxf基础见官网:http://cxf.apache.org/

  wsdl可通过官网工具生成、也能够通过eclipse直接生成

  spring相关参考关键字百度

时间: 2024-10-11 13:27:32

WebServcie结合Spring结合动态代理进行抽象封装以及性能优化的相关文章

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

今天项目经理发下任务,需要测试 20 个接口,看看推送和接收数据是否正常.因为对接传输的数据是 xml 格式的字符串,所以我拿现成的数据,先生成推送过去的数据并存储到文本,以便验证数据是否正确,这时候要批量调用这些同名方法,我觉得这里可以发展成有潜力的代码. 推送比较好做数据,队友们都写好代码,但是有个问题,方法要的值都大致相同,封装的方式不一致,多人开发,有的封装对象里面,有的直接使用 Map.get(),唉,一千个人一千个哈姆雷特嘛,只好利用反射和动态代理节省自己的代码量,而且这种方式练练手

详解 spring AOP 动态代理

通过例子查看,首先建立一个实现动态代理的接口Interface1.java,代码如下: package my.spring.fuck.aoptest; public interface Interface1 { public void say_hello(); } 很简单的一个接口,然后定义一个这个接口的实现类MyImple.java,代码: package my.spring.fuck.aoptest; public class MyImple implements Interface1{ @

Spring AOP动态代理实现,解决Spring Boot中无法正常启用JDK动态代理的问题

Spring AOP底层的动态代理实现有两种方式:一种是JDK动态代理,另一种是CGLib动态代理. JDK动态代理 JDK 1.3版本以后提供了动态代理,允许开发者在运行期创建接口的代理实例,而且只能为接口创建代理实例. 如果被代理目标没有接口那么Spring也无能为力,Spring通过Java的反射机制生成被代理接口的新的匿名实现类. JDK动态代理具体实现原理: 通过实现InvocationHandlet接口创建自己的调用处理器: 通过为Proxy类指定ClassLoader对象和一组in

Spring AOP动态代理

出现org.springframework.aop.framework.ProxyFactoryBean cannot be cast to 错误 在类型转换的时候, 调用getObject()方法,再对ProxyFactoryBean进行转换 xml文件 <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy><!--使用cglib动态代理--> <be

spring源码学习【准备】之jdk动态代理和cglib动态代理的区别和性能

一:区别:---->JDK的动态代理依靠接口实现,如果有些类并没有实现接口,则不能使用JDK代理,这就要使用cglib动态代理了.--->JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理. 性能:--->jdk的动态代理由于jdk版本的升级,渐渐超越cglib 二:都说 Cglib 创建的动态代理的

Spring之动态代理两种实现

基于jdk实现的动态代理 1 package com.proxy.daili; 2 3 import com.proxy.daili.service.IModelMath; 4 5 import java.lang.reflect.InvocationHandler; 6 import java.lang.reflect.Method; 7 import java.lang.reflect.Proxy; 8 import java.util.Arrays; 9 10 /** 11 * 动态代理模

Spring:利用PerformanceMonitorInterceptor来协助应用性能优化

前段时间对公司产品做性能优化.如果单依赖于测试,进度就会很慢.所以就想着通过对代码的方式来完成,并以此来加快项目进度.具体的执行方案自然就是要知道各个业务执行时间,针对业务来进行优化. 因为项目中使用了Spring,那自然的就想到要通过 Spring interceptor来完成这个事,然后就查了一下spring-aop.jar里,已有了多个trace,monitor相关的interceptor了.然后逐个看了一下,有一个PerformanceMonitorInterceptor,能够满足需求.

Spring AOP详解 、 JDK动态代理、CGLib动态代理

AOP是Aspect Oriented Programing的简称,面向切面编程.AOP适合于那些具有横切逻辑的应用:如性能监测,访问控制,事务管理以及日志记录.AOP将这些分散在各个业务逻辑中的代码通过横向切割的方式抽取到一个独立的模块中. 一.AOP术语 1.连接点(Joinpoint) 程序执行的某个特定位置:如类开始初始化之前.类初始化之后.类某个方法调用前.调用后等:一个类或一段程序代码拥有一些具有边界性质的特定点,这些代码中的特定点就成为“连接点”,Spring仅支持方法的连接点,即

Spring 容器AOP的实现原理——动态代理

参考:http://wiki.jikexueyuan.com/project/ssh-noob-learning/dynamic-proxy.html(from极客学院) 一.介绍 Spring的动态代理有两种:一是JDK的动态代理:另一个是cglib动态代理(通过修改字节码来实现代理). 今天主要讨论JDK动态代理的方式. JDK的代理方式主要就是通过反射跟动态编译来实现的,主要搭配InvocationHandler和Proxy来实现,下面的例子中使用了两层代理(即代理上加了一层代理). 二.