1、mybatis / jpa 等orm框架,可以在接口上加注解进行开发,不需要编写实现类,运行时动态产生实现。
2、dubbo等分布式服务框架,消费者只需要引入接口就可以调用远程的实现,分析源代码,其实在消费端产生了接口的代理实现,再由代理调用远程接口。
3、spring aop 这是最典型的动态代理了。
创建接口的动态实现,有二种最常用的方式:jdk动态代理和cglib动态代理。
代理模式是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个真实对象的访问。
代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。
通过代理层这一中间层,有效的控制对于真实委托类对象的直接访问,同时可以实现自定义的控制策略(spring的aop机制),设计上获得更大的灵活性。
下面用jdk动态代理加一点简单的代码来演示这个过程:
1、接口
1
2
3
4
5
|
package com.yhouse.modules.daos;
public interface iuserdao {
public string getusername();
}
|
2、创建代理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
package com.yhouse.modules.daos;
import java.lang.reflect.proxy;
/**
* 创建代理
* @author clonen.cheng
*
*/
public class invoker {
public object getinstance( class <?> cls){
methodproxy invocationhandler = new methodproxy();
object newproxyinstance = proxy.newproxyinstance(
cls.getclassloader(),
new class [] { cls },
invocationhandler);
return (object)newproxyinstance;
}
}
|
3、运行时调用接口的方法时的实现(这一过程也称为接口的方法实现)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
package com.yhouse.modules.daos;
import java.lang.reflect.invocationhandler;
import java.lang.reflect.method;
public class methodproxy implements invocationhandler {
@override
public object invoke(object proxy, method method, object[] args) throws throwable {
//如果传进来是一个已实现的具体类(本次演示略过此逻辑)
if (object. class .equals(method.getdeclaringclass())) {
try {
return method.invoke( this , args);
} catch (throwable t) {
t.printstacktrace();
}
//如果传进来的是一个接口(核心)
} else {
return run(method, args);
}
return null ;
}
/**
* 实现接口的核心方法
* @param method
* @param args
* @return
*/
public object run(method method,object[] args){
//todo
//如远程http调用
//如远程方法调用(rmi)
//....
return "method call success!" ;
}
}
|
4、测试
1
2
3
4
5
6
7
8
9
10
11
|
package com.yhouse.modules.daos;
public class proxytest {
public static void main(string[] args) {
iuserdao invoker=(iuserdao) new invoker().getinstance(iuserdao. class );
system.out.println(invoker.getusername());
}
}
|
在这段测试代码中,并没有接口的任何实现,大家猜猜会是什么结果?
控制台打印:
说明接口在调用时,把实现委托给了代理,最后具体要做的就是这个代理里面的处理:
在上面这段代码当中,可以看出,拿到了接口的method以及args,那么就可以做很多的事情,如根据方法名或者配合方法上面的注解来实现比较丰富的功能。
一个简单的例子只是用来说明这个原理,下面再举一个远程接口动态调用的例子来加深理解。
1、创建代理类和目标类需要实现共同的接口service
1
2
3
4
5
6
7
|
package com.markliu.remote.service;
/**
* service接口。代理类和被代理类抖需要实现该接口
*/
public interface service {
public string getservice(string name, int number);
}
|
2、服务器端创建remoteservice类,实现了service 接口。
1
2
3
4
5
6
7
8
9
10
11
|
package com.markliu.remote.serviceimpl;
import com.markliu.remote.service.service;
/**
* 服务器端目标业务类,被代理对象
*/
public class remoteservice implements service {
@override
public string getservice(string name, int number) {
return name + ":" + number;
}
}
|
3、创建封装客户端请求和返回结果信息的call类
为了便于按照面向对象的方式来处理客户端与服务器端的通信,可以把它们发送的信息用 call 类来表示。一个 call 对象表示客户端发起的一个远程调用,它包括调用的类名或接口名、方法名、方法参数类型、方法参数值和方法执行结果。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
package com.markliu.local.bean;
import java.io.serializable;
/**
* 请求的javabean
*/
public class call implements serializable{
private static final long serialversionuid = 5386052199960133937l;
private string classname; // 调用的类名或接口名
private string methodname; // 调用的方法名
private class <?>[] paramtypes; // 方法参数类型
private object[] params; // 调用方法时传入的参数值
/**
* 表示方法的执行结果 如果方法正常执行,则 result 为方法返回值,
* 如果方法抛出异常,那么 result 为该异常。
*/
private object result;
public call() {}
public call(string classname, string methodname, class <?>[] paramtypes, object[] params) {
this .classname = classname;
this .methodname = methodname;
this .paramtypes = paramtypes;
this .params = params;
}
// 省略了get和set方法
}
|
4、创建动态代理模式中实际的业务处理类,实现了invocationhandler 接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
package com.markliu.local.service;
import java.lang.reflect.invocationhandler;
import java.lang.reflect.method;
import com.markliu.local.bean.call;
public class serviceinvocationhandler implements invocationhandler {
private class <?> classtype;
private string host;
private integer port;
public class <?> getclasstype() {
return classtype;
}
public serviceinvocationhandler( class <?> classtype, string host, integer port) {
this .classtype = classtype;
this .host = host;
this .port = port;
}
@override
public object invoke(object proxy, method method, object[] args) throws throwable {
// 封装请求信息
call call = new call(classtype.getname(), method.getname(), method.getparametertypes(), args);
// 创建链接
connector connector = new connector();
connector.connect(host, port);
// 发送请求
connector.sendcall(call);
// 获取封装远程方法调用结果的对象
connector.close();
object returnresult = call.getresult();
return returnresult;
}
}
|
5、创建获取代理类的工厂remoteserviceproxyfactory
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
package com.markliu.local.service;
import java.lang.reflect.invocationhandler;
import java.lang.reflect.proxy;
/**
* 动态创建remoteservice代理类的工厂
*/
public class remoteserviceproxyfactory {
public static object getremoteserviceproxy(invocationhandler h) {
class <?> classtype = ((serviceinvocationhandler) h).getclasstype();
// 获取动态代理类
object proxy = proxy.newproxyinstance(classtype.getclassloader(),
new class []{classtype}, h);
return proxy;
}
}
|
6、创建底层socket通信的connector类,负责创建拦截、发送和接受call对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
package com.markliu.local.service;
// 省略import
/**
* 负责创建链接
*/
public class connector {
private socket linksocket;
private inputstream in;
private objectinputstream objin;
private outputstream out;
private objectoutputstream objout;
public connector(){}
/**
* 创建链接
*/
public void connect(string host, integer port) throws unknownhostexception, ioexception {
linksocket = new socket(host, port);
in = linksocket.getinputstream();
out = linksocket.getoutputstream();
objout = new objectoutputstream(out);
objin = new objectinputstream(in);
}
/**
* 发送请求call对象
*/
public void sendcall(call call) throws ioexception {
objout.writeobject(call);
}
/**
* 获取请求对象
*/
public call receive() throws classnotfoundexception, ioexception {
return (call) objin.readobject();
}
/**
* 简单处理关闭链接
*/
public void close() {
try {
linksocket.close();
objin.close();
objout.close();
in.close();
out.close();
} catch (ioexception e) {
e.printstacktrace();
}
}
}
|
7、创建远程服务器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
package com.markliu.remote.main;
// 省略import
public class remoteserver {
private service remoteservice;
public remoteserver() {
remoteservice = new remoteservice();
}
public static void main(string[] args) throws exception {
remoteserver server = new remoteserver();
system.out.println( "远程服务器启动......done!" );
server.service();
}
public void service() throws exception {
@suppresswarnings ( "resource" )
serversocket serversocket = new serversocket( 8001 );
while ( true ) {
socket socket = serversocket.accept();
inputstream in = socket.getinputstream();
objectinputstream objin = new objectinputstream(in);
outputstream out = socket.getoutputstream();
objectoutputstream objout = new objectoutputstream(out);
// 对象输入流读取请求的call对象
call call = (call) objin.readobject();
system.out.println( "客户端发送的请求对象:" + call);
call = getcallresult(call);
// 发送处理的结果回客户端
objout.writeobject(call);
objin.close();
in.close();
objout.close();
out.close();
socket.close();
}
}
/**
* 通过反射机制调用call中指定的类的方法,并将返回结果设置到原call对象中
*/
private call getcallresult(call call) throws exception {
string classname = call.getclassname();
string methodname = call.getmethodname();
object[] params = call.getparams();
class <?>[] paramstypes = call.getparamtypes();
class <?> classtype = class .forname(classname);
// 获取所要调用的方法
method method = classtype.getmethod(methodname, paramstypes);
object result = method.invoke(remoteservice, params);
call.setresult(result);
return call;
}
}
|
8、创建本地客户端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
package com.markliu.local.main;
import java.lang.reflect.invocationhandler;
import com.markliu.local.service.remoteserviceproxyfactory;
import com.markliu.local.service.serviceinvocationhandler;
import com.markliu.remote.service.service;
public class localclient {
public static void main(string[] args) {
string host = "127.0.0.1" ;
integer port = 8001 ;
class <?> classtype = com.markliu.remote.service.service. class ;
invocationhandler h = new serviceinvocationhandler(classtype, host, port);
service serviceproxy = (service) remoteserviceproxyfactory.getremoteserviceproxy(h);
string result = serviceproxy.getservice( "sunnymarkliu" , 22 );
system.out.println( "调用远程方法getservice的结果:" + result);
}
}
|
控制台打印结果:
这个过程可以简单的归纳为:本地接口调用(客户端)--->本地接口代理实现(客户端)---->远程实现(服务器端)
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:http://www.cnblogs.com/clonen/p/6735011.html