xiuli 的个人资料我的岛屿照片日志列表更多 工具 帮助
10月27日

好消息

移民法要变化了,希望能出现有利于我的变化.
天下还是很大的.
10月16日

最近总结的大实话

一群武断的人在和另外一群武断的人狗咬狗
最烦那种似乎看透别人的人以高姿态评价别人的行为
人一深刻就开始卖弄深刻,于是又肤浅了
思维就像病毒一样能传染.看看我们的投票都和天上掉下来的假设的钱有关系,就看出来已经传染开了.就不能来点高雅的吗? 
10月7日

总结java开发web service的方法

目前看到的有三种比较简单的方法:
1使用静态的stub
通过wsdl2java工具,处理相应ws的wsdl文件,我们可以得到远程ws的stub 直接调用这
个stub即可
AXIS提供的wsdl2java工具,如下:
java org.apache.axis.wsdl.WSDL2Java (WSDL-file-URL)
我们直接调用stub即可
eclipse也有相应的插件可以直接import wsdl来产生stub,如果你安装了EMF all in one版本的eclipse 3.1,就可以在视图里把Web Service的相关视图打开,接着就可以通过Web Service的Wizard来创建出相关的Web Service Client或者Server

2 Dynamic Proxy
根据远程wsdl,利用javax.xml.rpc.Service的getPort函数,可以得到远程ws的一个 D
ynamic Proxy
编写代理接口

public interface HelloClientInterface
extends Java.rmi.Remote
{
    public String getName(String name)
        throws Java.rmi.RemoteException;
}
 

客户端程序TestHelloClient.Java 

import Javax.xml.rpc.Service;
import Javax.xml.rpc.ServiceFactory;
import Java.net.URL;
import Javax.xml.namespace.QName;

public class TestHelloClient 
{
    public static void main(String[] args)
        {
        try
        {
   String wsdlUrl = "http://localhost:8080/axis/HelloClient.jws?wsdl";
   String nameSpaceUri = "http://localhost:8080/axis/HelloClient.jws";
String serviceName = "HelloClientService";
String portName = "HelloClient";
ServiceFactory serviceFactory = ServiceFactory.newInstance();
Service afService = serviceFactory.createService(new URL(wsdlUrl),
           new QName(nameSpaceUri, serviceName));
 HelloClientInterface proxy = (HelloClientInterface)afService.getPort(new QName(
              nameSpaceUri, portName), HelloClientInterface.class);
 System.out.println("return value is "+proxy.getName("john") ) ;
        }catch(Exception ex)
        {
            ex.printStackTrace() ;
        }
    }
}
 

3 DII
Dynamic Invocation Interface 这个最好理解,比如你动态获得了一个类,只知道类的
名字,你要调用他的一个方法,只好使用reflection得到你要调用的类,相应的参数信
息,然后调用
使用DII调用WS的时候,你知道的只是一个WSDL的地址,通过解析wsdl,你可以得到相应
的ws endpoint的信息,然后通过javax.xml.rpc.Call的setOperationName, addParam
eter等函数来指定要调用的函数,指定参数,然后调用
提供DII调用的原因是,我们有可能使用程序自动的去动态调用网络上的WS,而这个WS的
一切信息都是来自其WSDL
,只有通过DII,我们才有可能动态的去调用这个ws
例子:
服务器端程序

public class HelloClient
{
    public String getName(String name)
    {
        return "hello "+name;
    }
}
把源码拷贝到AXIS_HOME下,并改名为 HelloClient.jws

客户端程序
import org.apache.Axis.client.Call;
import org.apache.Axis.client.Service;
import Javax.xml.namespace.QName;
import Javax.xml.rpc.ServiceException;
import Java.net.MalformedURLException;
import Java.rmi.RemoteException;

public class SayHelloClient2
{
    public static void main(String[] args)
        {
        try
                {
  String endpoint =  "http://localhost:8080/axis/HelloClient.jws";

    Service service = new Service();
            Call call = null;

            call = (Call) service.createCall();

            call.setOperationName
   (new QName("http://localhost:8080/axis/HelloClient.jws", "getName"));
            call.setTargetEndpointAddress(new Java.net.URL(endpoint));

 String ret = 
 (String) call.invoke(new Object[] 
     {"zhangsan"});
  System.out.println
  ("return value is " + ret);
        } 
                catch (Exception ex)
                {
       ex.printStackTrace();
        }
    }
}

反向控制/依赖注入

在第2章中,笔者通过两个简单的实例展示了Spring的IoC功能,接下来将对Spring的IoC进行详细的讲解,因为Spring的核心就是IoC。在本章中,首先从IoC的基本思想开始,然后通过实例的方式使读者对其概念和工作原理有一个深入的了解,最后会把第2章中的第一个实例进行改编,使其通过构造方式来实现同样的功能。

3.1  反向控制/依赖注入

近年来,在Java社区中掀起了一股轻量级容器的热潮,几乎每隔一段时间,就会有新的轻量级容器出现,这些轻量级的容器能够较好地帮助开发者快速地将不同的组件组装成一个应用程序。在这些轻量级的容器的背后,有一个共同的模式决定着容器装配组件的方式,就是“反向控制”,即IoC,英文全称是Inversion of Control。Martin Fowler深入地探索了“反向控制”的工作原理,并为其起了一个新的名字叫做“依赖注入”,即DI,英文全称是Dependency Injection。关于Martin Fowler的这篇文章,读者可以在其网站上看到,网址是http://www.martinfowler.com/articles/injection.html。

3.1.1  反向控制(IoC)

单从字面上,其实很难理解“反向控制”所要表达的含义。其实在编程时,开发人员常说的“实现必须依赖抽象,而不是抽象依赖实现”就是“反向控制”的一种表现方式。下面,笔者主要通过举例来说明这个抽象的概念。这个实例主要说明的是如何通过IoC来实现业务逻辑从哪种数据库中取数据的问题。可能的取数据方式有3种,分别是:

  ●       从SQL Server数据库中取数据。

  ●       从DB2数据库中取数据。

  ●       从Oracle数据库中取数据。

介绍这个实例的思路是:首先介绍编写这类程序通常的做法,然后指出这种做法的不足,接着给出一种比较好的做法,即通过IoC来实现这类功能,最后对这种做法进行总结,使读者一步一步地了解IoC。编写这类程序通常做法的具体步骤如下:

(1)通常编写这类程序都是先编写一个从数据库取数据的类SqlServerDataBase.java,这里以从SQL Server数据库中取数据为例。SqlServerDataBase.java的示例代码如下。其中getDataFromSqlServer()是SqlServerDataBase类中的一个方法,具体负责从SQL Server数据库中取数据。

//******* SqlServerDataBase.java**************

public class SqlServerDataBase {

         ……

    //从SQLServer数据库中获取数据

         public List getData() {

                   ……

         }

}

(2)业务逻辑类Business.java通过SqlServerDataBase.java中的方法来从SQL Server数据库中取数据。Business.java的示例代码如下。其中SqlServerDataBase是用来从SQL Server数据库中取数据的类。

//******* Business.java**************

public class Business {

         private SqlServerDataBase db = new SqlServerDataBase();

         ……

    //从SQL Server数据库中获取数据

         public void getData() {

                   ……

    List list = db.getDataFromSqlServer();

    ……

         }

}

可以看出以上程序编写的不足之处:Business类依赖于SqlServerDataBase类,如果业务改变,用户现在要求从DB2或Oracle数据库中取数据,则这个程序就不适用了,必须要修改Business类。

(3)改为从DB2数据库中取数据,DB2DataBase.java的示例代码如下。其中getDataFrom DB2()是DB2DataBase类中的一个方法,具体负责从DB2数据库中取数据。

//******* DB2DataBase.java**************

public class DB2DataBase {

         ……

         //从DB2数据库中获取数据

         public List getData() {

                   ……

         }

}

(4)必须修改业务逻辑类Business.java,改为从DB2数据库中取数据。Business.java的示例代码如下,其中DB2DataBase是用来从DB2数据库中取数据的类。

//******* Business.java**************

public class Business {

         private DB2DataBase db = new DB2DataBase();

         ……

         //从DB2数据库中获取数据

         public void getData() {

                   ……

                   List list = db.getDataFromDB2();

                   ……

         }

}

(5)同样,用户现在要求从Oracle数据库中取数据,则这个程序就不适用了。改为从Oracle数据库中取数据,OracleDataBase.java的示例代码如下。其中getDataFromOracle ()是OracleDataBase类中的一个方法,具体负责从Oracle数据库中取数据。

//******* OracleDataBase.java**************

public class OracleDataBase {

         ……

         //从Oracle数据库中获取数据

         public List getData() {

                   ……

         }

}

(6)还要修改业务逻辑类Business.java,改为从Oracle数据库中取数据。Business.java的示例代码如下。其中OracleDataBase是用来从Oracle数据库中取数据的类。

//******* Business.java**************

public class Business {

         private OracleDataBase db = new OracleDataBase();

         ……

         //从Oracle数据库中获取数据

         public void getData() {

                   ……

                   List list = db.getDataFromOracle ();

                   ……

         }

}

至此,读者应该可以发现了,这可不是一个好的设计,因为每次业务需求的变动都要导致程序的大量修改,怎样才能改变这种情形的发生呢?怎样才能实现Business类的重用呢?IoC就可以解决这个问题,它可以通过面向抽象编程来改变这种情况。

下面就利用IoC来实现Business类的重用,编写思路是:首先编写一个获取数据的接口,然后每个具体负责从各种数据库中获取数据的类都实现这个接口,而在业务逻辑类中,则根据接口编程,并不与具体获取数据的类打交道。通过IoC来实现这个功能的具体步骤如下。

(1)编写用来获取数据的接口DataBase。DataBase.java的示例代码如下:

//******* DataBase.java**************

public interface DataBase {

         //该方法用来获取数据

         public void getData();

}

(2)编写具体负责从SQL Server数据库中取数据的类SqlServerDataBase,该类实现了接口DataBase。SqlServerDataBase.java的示例代码如下:

//******* SqlServerDataBase.java**************

public class SqlServerDataBase implement DataBase {

         //该方法用来获取数据

         public void getData() {

                   //以下是具体从SQL Server数据库中取数据的代码

                   ……

         }

}

(3)编写业务逻辑类Business,该类只针对接口DataBase编码,而不针对实体类。Business.java的示例代码如下:

//******* Business.java**************

public class Business {

         //针对接口DataBase定义变量

         private DataBase db;

         public void setDataBase(DataBase db) {

                   this.db = db;

         }

         ……

         //根据注入的数据库类,从×××数据库中获取数据

         public void getData() {

                   ……

                   db.getData();

                   ……

         }

}

(4)编写测试类TestBusiness。TestBusiness.java的示例代码如下:

//******* TestBusiness.java**************

public class TestBusiness {

         private Business business = new Business();

         ……

         //根据注入的数据库类,从SQL Server数据库中获取数据

         public void getData() {

                   ……

                   business. setDataBase(new SqlServerDataBase());

                   business.getData();

                   ……

         }

}

通过这种方式Business类就可以重用了,不管从哪种数据库中获取数据,Business类都不用改动,只需要实现具体的DataBase接口就可以了。例如,用户要求改为从DB2数据库中获取数据,只要实现一个具体负责从DB2数据库中取数据的类就可以了。

(5)编写具体负责从DB2数据库中取数据的类DB2DataBase,该类实现了接口DataBase。DB2DataBase.java的示例代码如下:

//******* DB2DataBase.java**************

public class DB2DataBase implement DataBase {

         public void getData() {

                   //以下是具体从DB2数据库中取数据的代码

                   ……

         }

}

(6)业务逻辑类Business不用作任何改动,修改测试类TestBusiness。TestBusiness.java的示例代码如下:

//******* TestBusiness.java**************

public class TestBusiness {

         private Business business = new Business();

         ……

         //根据注入的数据库类,从DB2数据库中获取数据

         public void getData() {

                   ……

                   business. setDataBase(new DB2DataBase());

                   business.getData();

                   ……

         }

}

(7)如果用户又要求改为从Oracle数据库中获取数据,只要实现一个具体负责从Oracle数据库中取数据的类就可以了。编写具体负责从Oracle数据库中取数据的类OracleDataBase,该类实现了接口DataBase。OracleDataBase.java的示例代码如下:

//******* OracleDataBase.java**************

public class OracleDataBase implement DataBase {

         public void getData() {

                   //以下是具体从Oracle数据库中取数据的代码

                   ……

         }

}

(8)业务逻辑类Business不用作任何改动,修改测试类TestBusiness。TestBusiness.java的示例代码如下:

//******* TestBusiness.java**************

public class TestBusiness {

         private Business business = new Business();

         ……

         //根据注入的数据库类,从Oracle数据库中获取数据

         public void getData() {

                   ……

                   business. setDataBase(new OracleDataBase());

                   business.getData();

                   ……

         }

}

从上面的例子可以看到,在第一个例子中,使用通常的做法,Business类依赖于具体获取数据的类;而在第二个例子中,通过接口来编程,即控制关系的反向转移,实现了IoC功能,并使代码获得了重用。这也就实现了上面所说的“实现必须依赖抽象,而不是抽象依赖实现”。

3.1.2  依赖注入(DI)

Martin Fowler在其文章中提出了“它们反转了哪方面的控制”的问题后,就为IoC起了一个更能说明这种模式特点的新名字,叫做“依赖注入”,即Dependency Injection,Spring就是使用Dependency Injection来实现IoC功能,接着Martin Fowler介绍了Dependency Injection的3种实现方式,接下来笔者将结合上面的例子对这3种实现方式进行详细的讲解。

3.2  依赖注入的3种实现方式

在讲解依赖注入的3种实现方式之前,这里先澄清一下依赖注入的意义:让组件依赖于抽象,当组件要与其他实际对象发生依赖关系时,通过抽象来注入依赖的实际对象。

依赖注入的3种实现方式分别是:接口注入(interface injection)、Set注入(setter injection)和构造注入(constructor injection)。接下来笔者还将主要通过举例的方式,把依赖注入的3种实现方式介绍给读者。

3.2.1  接口注入(interface injection)

接口注入指的就是在接口中定义要注入的信息,并通过接口完成注入。结合前面的示例,其具体步骤如下。

(1)编写一个接口IBusiness,各种数据库的注入将通过这个接口进行。IBusiness.java的示例代码如下:

//******* IBusiness.java**************

public interface IBusiness {

         public void createDI(DataBase db);

}

(2)任何想要使用数据库实例的类都必须实现这个接口,业务逻辑类Business实现这个接口IBusiness。Business.java的示例代码如下:

//******* Business.java**************

public class Business implement IBusiness {

         private DataBase db;

         public void createDI (DataBase db) {

                   this.db = db;

         }

         ……

         //根据注入的数据库类,从×××数据库中获取数据

         public void getData() {

                   ……

                   db.getData();

                   ……

         }

}

(3)编写测试类TestBusiness。TestBusiness.java的示例代码如下:

//******* TestBusiness.java**************

public class TestBusiness {

         private Business business = new Business();

         ……

         //根据注入的数据库类,从Oracle数据库中获取数据

         public void getData() {

                   ……

                   business. createDI (new OracleDataBase());

                   business.getData();

                   ……

         }

}

如果要完成依赖关系注入的对象,必须实现IBusiness接口。

3.2.2  Set注入(setter injection)

Set注入指的就是在接受注入的类中定义一个Set方法,并在参数中定义需要注入的元素。为了让类Business接受DataBase的注入,需要为它定义一个Set方法来接受DataBase的注入。Business.java的示例代码如下:

//******* Business.java**************

public class Business {

         private DataBase db;

         public void setDataBase(DataBase db) {

                   this.db = db;

         }

         ……

         //根据注入的数据库类,从×××数据库中获取数据

         public void getData() {

                   ……

                   db.getData();

                   ……

         }

}

更详细的代码,可以参看3.1节的第二个例子,采用的就是Set注入的方式。

3.2.3  构造注入(constructor injection)

构造注入指的就是在接受注入的类中定义一个构造方法,并在参数中定义需要注入的元素。为了让类Business接受DataBase的注入,需要为它定义一个构造方法,来接受DataBase的注入。Business.java的示例代码如下:

//******* Business.java**************

public class Business {

         private DataBase db;

         public Business (DataBase db) {

                   this.db = db;

         }

         ……

         //根据注入的数据库类,从×××数据库中获取数据

         public void getData() {

                   ……

                   db.getData();

                   ……

         }

}