最近在项目中实现一个Webservice功能的时候,对反射的强大与运用又多了一点点认识。反射让我们的代码更加的灵活,更加的优美。
我们项目中有时候会有这样的需求:比如需要从别的应用系统中获取数据,比如在对自己系统的数据进行增删改的时候需要对另一个系统进行数据的同步处理。这个时候我们需要用到Webservice。第三方系统会提供给我们一个wsdl文件,里面规范出了所有的接口以及接口的参数。然后我们通过这个文件,构造出对应的符合它接口规范的webservice调用程序。
比如我最近在项目中遇到这样的一个需求:统一支撑平台中对部门和用户进行新增和修改的时候,要通过Webservice调用第三方的接口,对另一个库进行数据的同步处理。
一个很自然的实现方式是:在部门和用户的新增以及修改操作的地方,添加一段调用Webservice接口的代码,符合当前这个第三方提供的接口规范。一般我们都有一个系统参数来控制是否启用Webservice服务,来达到开关控制的目的,所以我们的调用Webservice接口的代码将会出现在4个地方,如果加上部门管理中相似的内容,那么我们这些代码将会出现在8个地方。很显然,这样做可以满足当前的需求,很直观。但是细想一下,却是不够灵活,不够通用。比如这个第三方提供的接口要是变 了,无论是接口名字,参数个数,或者接口的内容,只要它的规范出现了变化,那么我们就必须同步修改这8个地方,显而易见,这是个麻烦活,尤其重要的一点是,这些都是基础框架的内容。统一支撑平台是基于基础框架的,所以这样做带来的不利有如下几个方面:
1.接口的变化带来了框架的变化,框架的稳定性得不到保证
2.每次接口变化,都必须修改8个地方,甚至更多,工作量以及后续的测试肯定增加
3.最最痛苦的是:这些地方很可能绝大部门是相同的代码。
如果我们可以做出一个通用的Webservice调用方法,那么,上面的问题将迎刃而解。
首先,我们肯定需要统一Webservice调用的入口,也就是说,所有需要调用Webservice接口的地方使用的都是同一个函数。这是一个从特殊到一般的过程,也就是通常我们说的抽象。为此,我专门准备了一个中间类WebserviceUtilService:里面有个通用的函数:public String invokeWebService(String func,String guid),返回的是个调用信息,成功or失败
这个类做如下几件事:
1.获取系统参数IsUseWebService,判断是否启用Webservice
2.根据Webservice的接口信息,构造出符合接口调用规范的信息
3.通过真正的WerbserviceUtil这个工具类来invoke相应的方法
很明显:最重要的是第2步。这个动作发生在基础框架中,而Webservice的接口信息却是在各个子系统中才能最终确定,比如在统一支撑平台中。也就是说,基础框架需要调用子系统的某个方法,来获取Webservice的接口信息。这里使用反射可以实现。反射子系统的某个类的某个方法。比如子系统有个类叫WebServiceMsg,里面有个方法getMsg(String func,String guid),返回的是封装好的符合接口规范的Webservice接口调用的信息:包括要调用一个Webservice的方法,需要的url,serviceName,targetNameSpace,接口名字(方法名字),要传递的接口参数(是个Object数组)。这些信息通常会被封装成一个对象,这里我们叫它:WebserviceMethod。getMsg(String func,String guid)这个方法返回的是个WebserviceMethod的列表,因为一个操作可能需要调用多个接口。
这里用部门的新增做下例子:
1.在基础框架的新增部门的地方,我们通过WebserviceUtilService调用invokeWebService方法,传入2个参数分别是:"OU_ADD",你当前新增的部门的唯一guid
2.获取系统参数IsUseWebService,判断是否启用Webservice,如果启用,进行第三步
3.要反射一个类,那么需要知道这个类的包名+类名这样的全路径,我们这里将WebServiceMsg这样的子系统的类的全路径的信息保存在配置文件中。这里先从配置文件中获取路径,然后反射调用它的getMsg(String func,String guid)方法,传入的就是上面传进来的2个参数:"OU_ADD",你当前新增的部门的唯一guid
4.我们来具体看下子系统实现的WebServiceMsg这个类的getMsg(String func,String guid)这个方法:
public List<WebserviceMethod>getMsg(String func,String guid)
{
if(func.equals("OU_ADD"))
{
1.新建1个WebserviceMethod,用来保存1个需要调用的WebService接口的信息
2.根据guid,我们可以查询出要新增的部门的所有信息,然后根据接口规范,封装成一个Object[]。假如这个第三方的系统的部门新增的接口名字是"dept_add",参数分别是:ouname,ouguid,parentouguid,ordernumber.那么我们封装好的Object[]肯定长度为4,里面的信息分别对应部门的名字,guid,父部门的guid,排序号。
3.其它信息诸如url,serviceName,targetNameSpace都可以从第三方给的wsdl这个Webservice接口规范文件里面获取。
4.这样我们就成功获取到了调用这个第三方系统的dept_add方法的所需要的所有信息。
5.如果我们在新增部门的同时,还需要往兼职部门里面同步数据,那么我们需要根据兼职部门新增的接口再次构造出一个WebserviceMethod对象
6.最后我们返回所有的WebserviceMethod。
}
}
5.这下子可以直接通过WebServiceUtil这个类,传入url,serviceName,targetNameSpace,接口名字(方法名字),要传递的接口参数(是个Object数组)这些参数来调用真正的Webservice接口了。也就达到了同步第三方数据的目的。
综上:我们基本实现了最初的需求,如果每个子系统由第三方提供的接口都不一样,那么我们仅仅需要实现或者修改一个类WebServiceMsg中的一个方法:getMsg即可。基础框架无需变更,其他调用地方也不需要修改。完全符合面向对象的设计原则:开闭原则:对修改关闭,对扩展开放。比如接口的名字变了,不再是dept_add,而是OU_ADD,比如参数顺序,参数个数变了,我们也只要修改相应的Object数组即可。
当然,这一切的成功都源于反射提供给我们的动态特性。
我们项目中有时候会有这样的需求:比如需要从别的应用系统中获取数据,比如在对自己系统的数据进行增删改的时候需要对另一个系统进行数据的同步处理。这个时候我们需要用到Webservice。第三方系统会提供给我们一个wsdl文件,里面规范出了所有的接口以及接口的参数。然后我们通过这个文件,构造出对应的符合它接口规范的webservice调用程序。
比如我最近在项目中遇到这样的一个需求:统一支撑平台中对部门和用户进行新增和修改的时候,要通过Webservice调用第三方的接口,对另一个库进行数据的同步处理。
一个很自然的实现方式是:在部门和用户的新增以及修改操作的地方,添加一段调用Webservice接口的代码,符合当前这个第三方提供的接口规范。一般我们都有一个系统参数来控制是否启用Webservice服务,来达到开关控制的目的,所以我们的调用Webservice接口的代码将会出现在4个地方,如果加上部门管理中相似的内容,那么我们这些代码将会出现在8个地方。很显然,这样做可以满足当前的需求,很直观。但是细想一下,却是不够灵活,不够通用。比如这个第三方提供的接口要是变 了,无论是接口名字,参数个数,或者接口的内容,只要它的规范出现了变化,那么我们就必须同步修改这8个地方,显而易见,这是个麻烦活,尤其重要的一点是,这些都是基础框架的内容。统一支撑平台是基于基础框架的,所以这样做带来的不利有如下几个方面:
1.接口的变化带来了框架的变化,框架的稳定性得不到保证
2.每次接口变化,都必须修改8个地方,甚至更多,工作量以及后续的测试肯定增加
3.最最痛苦的是:这些地方很可能绝大部门是相同的代码。
如果我们可以做出一个通用的Webservice调用方法,那么,上面的问题将迎刃而解。
首先,我们肯定需要统一Webservice调用的入口,也就是说,所有需要调用Webservice接口的地方使用的都是同一个函数。这是一个从特殊到一般的过程,也就是通常我们说的抽象。为此,我专门准备了一个中间类WebserviceUtilService:里面有个通用的函数:public String invokeWebService(String func,String guid),返回的是个调用信息,成功or失败
这个类做如下几件事:
1.获取系统参数IsUseWebService,判断是否启用Webservice
2.根据Webservice的接口信息,构造出符合接口调用规范的信息
3.通过真正的WerbserviceUtil这个工具类来invoke相应的方法
很明显:最重要的是第2步。这个动作发生在基础框架中,而Webservice的接口信息却是在各个子系统中才能最终确定,比如在统一支撑平台中。也就是说,基础框架需要调用子系统的某个方法,来获取Webservice的接口信息。这里使用反射可以实现。反射子系统的某个类的某个方法。比如子系统有个类叫WebServiceMsg,里面有个方法getMsg(String func,String guid),返回的是封装好的符合接口规范的Webservice接口调用的信息:包括要调用一个Webservice的方法,需要的url,serviceName,targetNameSpace,接口名字(方法名字),要传递的接口参数(是个Object数组)。这些信息通常会被封装成一个对象,这里我们叫它:WebserviceMethod。getMsg(String func,String guid)这个方法返回的是个WebserviceMethod的列表,因为一个操作可能需要调用多个接口。
这里用部门的新增做下例子:
1.在基础框架的新增部门的地方,我们通过WebserviceUtilService调用invokeWebService方法,传入2个参数分别是:"OU_ADD",你当前新增的部门的唯一guid
2.获取系统参数IsUseWebService,判断是否启用Webservice,如果启用,进行第三步
3.要反射一个类,那么需要知道这个类的包名+类名这样的全路径,我们这里将WebServiceMsg这样的子系统的类的全路径的信息保存在配置文件中。这里先从配置文件中获取路径,然后反射调用它的getMsg(String func,String guid)方法,传入的就是上面传进来的2个参数:"OU_ADD",你当前新增的部门的唯一guid
4.我们来具体看下子系统实现的WebServiceMsg这个类的getMsg(String func,String guid)这个方法:
public List<WebserviceMethod>getMsg(String func,String guid)
{
if(func.equals("OU_ADD"))
{
1.新建1个WebserviceMethod,用来保存1个需要调用的WebService接口的信息
2.根据guid,我们可以查询出要新增的部门的所有信息,然后根据接口规范,封装成一个Object[]。假如这个第三方的系统的部门新增的接口名字是"dept_add",参数分别是:ouname,ouguid,parentouguid,ordernumber.那么我们封装好的Object[]肯定长度为4,里面的信息分别对应部门的名字,guid,父部门的guid,排序号。
3.其它信息诸如url,serviceName,targetNameSpace都可以从第三方给的wsdl这个Webservice接口规范文件里面获取。
4.这样我们就成功获取到了调用这个第三方系统的dept_add方法的所需要的所有信息。
5.如果我们在新增部门的同时,还需要往兼职部门里面同步数据,那么我们需要根据兼职部门新增的接口再次构造出一个WebserviceMethod对象
6.最后我们返回所有的WebserviceMethod。
}
}
5.这下子可以直接通过WebServiceUtil这个类,传入url,serviceName,targetNameSpace,接口名字(方法名字),要传递的接口参数(是个Object数组)这些参数来调用真正的Webservice接口了。也就达到了同步第三方数据的目的。
综上:我们基本实现了最初的需求,如果每个子系统由第三方提供的接口都不一样,那么我们仅仅需要实现或者修改一个类WebServiceMsg中的一个方法:getMsg即可。基础框架无需变更,其他调用地方也不需要修改。完全符合面向对象的设计原则:开闭原则:对修改关闭,对扩展开放。比如接口的名字变了,不再是dept_add,而是OU_ADD,比如参数顺序,参数个数变了,我们也只要修改相应的Object数组即可。
当然,这一切的成功都源于反射提供给我们的动态特性。