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