当前位置: 代码迷 >> Web前端 >> 在WebService中运用动态代理模式和Annotation注解
  详细解决方案

在WebService中运用动态代理模式和Annotation注解

热度:167   发布时间:2012-11-01 11:11:33.0
在WebService中使用动态代理模式和Annotation注解

公司接口程序,使用的是直接读取XMl, 然后使用XStream解析返回的 XML 返回生成的对象。?

?

设计中使用了动态代理的模式,

?

并且结合自定义注解来定义常量和传递的参数 。

?

动态代理 :

?

定义了接口 Feed 及相应的方法, 使用注解传递参数和常量 。

?

?

@DefaultParams(@DefaultParam(key="apikey",value=Feed.APIKEY))

@ServiceURL("https://xml.xxxxxx.com/datafeed/Feed.asmx")

public interface Feed {

	/** 提供服务标识 */

	public static final String APIKEY = "82DD63FF-A7EB-47XXXXXXXXXXXXXX";

	/** 获取地区 */

	@GetMethod
	@HotelCache(timeoutByHour=24*7)
	@MethodName("GetFeed")
	@DefaultParams(@DefaultParam(key="feed_id",value="1"))
	@XStreamRoot("/Region_feed/regions")
	@XStreamAnnotation(@XStreamAlias(key="region",value=RegionFeed.class))
	public List<RegionFeed>  getRegionFeed();

}
	
?

在 Action 初始化的时候, 加载 Feed 接口的动态代理:

?

public class HotelListAction extends BaseAction {

	static {

		defaultParams = new ArrayList<Object>();
		FeedDefaultParam param = new FeedDefaultParam();
		param.setOlanguage_id(LEAGUAGE_CODE);
		defaultParams.add(param);
		feed = IXRProxyFactory.newProxyInstance(Feed.class,defaultParams);
	}

	public void geoCity() {
		CityFeedParams params = new CityFeedParams();
		params.setMcountry_id(id);
		List<CityFeed> cities = null;
		try{
			cities = feed.getCityFeed(params);
		}catch(Exception ex){
			logger.error("查找城市不存在!");
		}	

		outputPlainText(JSONArray.fromObject(cities).toString());
	}

}
?

这里使用了自定义的代理工厂,

?

/**
 * 代理工厂
 * @version 1.0 2010-12-4
 * @author ixr_(mail@ixr.name)
 */
public class IXRProxyFactory{
    /** 获取代理对象 */
    public static <T> T newProxyInstance(Class<T> interfaceClass,List<Object> defaultParams){
        IXRProxy proxy = new IXRProxy();
        proxy.setDefaultParams(defaultParams);
        proxy.setInterfaceClass(interfaceClass);
        Object proxyImpl = Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class[]{interfaceClass}, proxy);
        return interfaceClass.cast(proxyImpl);
    }
}
?

其中 ,IXRProxy 就是代理处理逻辑类 ,其继承接口 InvocationHandler? ,实现方法:

public Object invoke(Object proxy, Method method, Object[] args)

此方法体, 会代替被代理接口的每个方法执行,并且返回? Object 对象。

?

public class IXRProxy implements InvocationHandler{

    /** 默认编码 */
    private static final String ENCODING = "utf-8";
    /** 接口 */
    private Class<?> interfaceClass = null;
    
    public void setInterfaceClass(Class<?> interfaceClass){
    	this.interfaceClass = interfaceClass;
    }
    
    /** 默认参数 */
    private List<Object> defaultParams = new ArrayList<Object>();
    public void setDefaultParams(List<Object> defaultParams){
        this.defaultParams = defaultParams;
    }
    
    private Object invoke(Object proxy, HttpClientParam httpClientParam, Method method, Object[] args) throws Throwable {
String xml = null;
        try {
            if(httpClientParam.isGet){
            	xml = HttpClientUtils.getHTML(httpClientParam.url, httpClientParam.params);
            }else{
            	xml = HttpClientUtils.postHTML(httpClientParam.url, httpClientParam.params);
            }
                XStreamAnnotation xStreamAnnotation = method.getAnnotation(XStreamAnnotation.class);
                if (xStreamAnnotation != null) {
                    XStreamAlias[] xStreamAliasArray = xStreamAnnotation.value();
                    for (XStreamAlias xStreamAlias : xStreamAliasArray) {
                        xStream.alias(xStreamAlias.key(), xStreamAlias.value());
                        String[] useAttributes = xStreamAlias.useAttributes();
                        for (String useAttribute : useAttributes) {
                        	xStream.useAttributeFor(xStreamAlias.value(), useAttribute);
                        }
                    }
                   
                }
                Document dom = DocumentHelper.parseText(xml);
                
                return xStream.fromXML(xml);
            } else {
                return null;
            }
        } catch (Exception e) {
        	log.error("取接口数据时出错", e);
        	
        	return null;
        }
    }
?

?

代理方法中, 根据接口定义的注解参数, 转换返回的 XML 所对应的类型, 并且返回。

?

自定义注解 :

?

自定义的注解接口 :

?

public interface IXRProxyAnnotation {
    /** 服务地址 */
    @Documented
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ServiceURL{
        String value(); 
    }
    /** XStream解析类型 */
    @Documented
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface XStreamAnnotation{
        XStreamAlias[] value();
        AttributeValueConveter[] attributeValueConveters() default {};
    }
    /** XStream解析根目录 */
    @Documented
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface XStreamRoot{
        String value();
    }
    /** XStream解析类型映射 */
    @Documented
    @Target(ElementType.PARAMETER)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface XStreamAlias{
        String key();
        Class<?> value();
        String[] useAttributes() default {};
    }


}
?

注解中, 可定义

??????? String key();
??????? Class<?> value();
??????? String[] useAttributes() default {};

等等参数, 标注注解的时候, 需要提供这些默认值 。。

?

@XStreamAlias(key="country",value=CountryFeed.class)
?

在 invoke 方法中, 通过接口类对象的方法:

//获取接口参数
??????? String serviceURL = interfaceClass.getAnnotation(ServiceURL.class).value();

?

通过参数: Method method 得到方法标记的参数

//方法标记参数
??????? DefaultParams defaultParamsAnnotation = method.getAnnotation(DefaultParams.class);
??????? if(defaultParamsAnnotation != null){
??????????? for (DefaultParam defaultParam : defaultParamsAnnotation.value()) {
?????????? ??? ?params.put(defaultParam.key(), defaultParam.value());
??????????? }
??????? }

?

获得传入的参数:

?

        //获取传入参数
        for (Object param : (args == null ? new Object[0] : args)) {
            argsList.add(param);
        }
        //转换请求参数列表
        for (Object param : argsList) {
            Field[] fiedl = param.getClass().getDeclaredFields();
            for (Field field : fiedl) {
                Param paramAnnotation = field.getAnnotation(Param.class);
                if (paramAnnotation != null) {
                    field.setAccessible(true);
                    params.put(paramAnnotation.value().isEmpty() ? field.getName() : paramAnnotation.value(), String.valueOf(field.get(param)));
                }
            }
        }
?

比如,在获取城市数据的时候, 传入参数定义的类 :

?

public class CityFeedParams {
	@Param private Integer mcountry_id; //--国家ID

	public Integer getMcountry_id() {
		return mcountry_id;
	}

	public void setMcountry_id(Integer mcountry_id) {
		this.mcountry_id = mcountry_id;
	}

}

?

必须要在变量前面加自定义注解: @Param

?

才能在invoke方法中,使用 Param paramAnnotation = field.getAnnotation(Param.class); 得到值,传出到Webservice...

?

?

?

1 楼 IXR 2011-05-26  
  允许我转载下吗?
2 楼 Jxdwuao 2011-05-26  
我晕, 你是 .. 王雪? 
  相关解决方案