先举个静态代理的例子,可能多少有些不恰当,不过本次学习记录,重点不在于通信协议。 比如你在一个机房里,你不能联网,只能连通过一台能连公网的代理机器上网。你发送了一个http请求,将由代理帮你上网。
首先有一个HttpMessage接口,InternetProxy(公网代理)和LANMessage(局域网发消息) 都实现HttpMessage接口。公网代理将代理LANMessage上网。实际上代理模式,增强了原来对象的方法,并且无侵入性,不需要修改原有代码。
1 public interface HttpMessage { 2 void sendMsg(String msg); 3 }
1 public class LANMessage implements HttpMessage { 2 @Override 3 public void sendMsg(String msg) { 4 System.out.println("lan send msg"); 5 } 6 }
1 public class InternetProxy implements HttpMessage { 2 3 //被代理的对象 4 LANMessage message; 5 6 @Override 7 public void sendMsg(String msg) { 8 before(); 9 message.sendMsg(msg); 10 after(); 11 } 12 13 void before() { 14 System.out.println("prepare internet msg"); 15 } 16 17 void after() { 18 System.out.println("after internet msg"); 19 } 20 }
上面只是一个静态代理增强对象的示例。当代码中有大量的 需要增强,甚至动态增强的代码时,这种代理类,会遍布项目中到处都是,并且当接口改变,代理类和实现类都要一并修改。所以有了动态代理。
jdk动态代理:
无需创建代理类,直接使用,会生成class文件,class文件也将被加载到内存中的Class对象,有了class对象,就有了类的所有信息,在调用方法的时候,动态代理相当于拦截了我们所有的调用,你可以在invoke中对目标对象和其方法进行增强。也应该不难想到,new instance 基本上就是通过拿到的class对象,来拿到其Contrustor 来构造对象。如果反编译生成的class文件,也可以看到在调用方法的时候,刚实现的invoke方法会被调用。 Class对象在手,天下我有~
1 public class TestProxy { 2 3 LANMessage msg=new LANMessage(); 4 @Test 5 public void fun(){ 6 HttpMessage message=(HttpMessage) Proxy.newProxyInstance(LANMessage.class.getClassLoader(), LANMessage.class.getInterfaces(), new InvocationHandler() { 7 @Override 8 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 9 System.out.println("before"); 10 Object res= method.invoke(msg,args); 11 System.out.println("after"); 12 return res; 13 } 14 }); 15 message.sendMsg("hello"); 16 } 17 }
CGLib方式:
该方式可代理任何类 不需要提供接口。其生成的class字节码文件,反编译后可以看到 它生成的是委托类的子类。
1 public class TestProxy { 2 3 LANMessage msg = new LANMessage(); 4 5 @Test 6 public void fun() { 7 8 CGLibProxy proxy=new CGLibProxy(); 9 HttpMessage msg=(HttpMessage) proxy.getProxy(LANMessage.class); 10 msg.sendMsg("hi"); 11 } 12 } 13 14 class CGLibProxy implements MethodInterceptor { 15 16 public Object getProxy(Class<?> clazz) { 17 return Enhancer.create(clazz, this); 18 } 19 20 @Override 21 public Object intercept(Object o, Method method, Object[] args, MethodProxy proxy) throws Throwable { 22 System.out.println("before"); 23 Object res = proxy.invokeSuper(o, args); 24 System.out.println("afert"); 25 return res; 26 } 27 }