java动态代理详解
记录学习的每一点过程
本文主要介绍的是动态代理,所以静态代理在这里就简单介绍一下
1、静态代理
静态代理的角色介绍
抽象角色:一般是接口或者是抽象类
1 /** 2 * 抽象角色:以租房为例,这是一个租房子的接口 3 */ 4 public interface Rent { 5 void rent(); 6 }
真实角色:被代理的角色
1 /** 2 * 文件名:Host 3 * 作 者:zyz 4 * 时 间:2019/6/12 9:47 5 * ------------------------- 6 * 功能和描述:真实角色,实现抽象角色对应的接口(Rent) 7 **/ 8 public class Host implements Rent{ 9 public void rent(){ 10 System.out.println("房屋出租"); 11 } 12 }
代理角色:代理真实角色,代理真实角色之后,一般会做一些附属(增强的操作)
1 /** 2 * 代理角色:同真实角色实现同一个接口 3 */ 4 public class Proxy implements Rent { 5 private Host host; 6 7 public Proxy() { 8 } 9 10 public Proxy(Host host) { 11 this.host = host; 12 } 13 14 public void setHost(Host host) { 15 this.host = host; 16 } 17 18 public void rent() { 19 seeHouse(); 20 host.rent(); 21 fee(); 22 } 23 24 25 //**************代理角色附带(增强)的一些功能**************// 26 private void seeHouse(){ 27 System.out.println("带租客看房子"); 28 } 29 private void fee(){ 30 System.out.println("收取中介费"); 31 } 32 }
测试类
1 /** 2 * 文件名:Client 3 * 作 者:zyz 4 * 时 间:2019/6/12 9:47 5 * ------------------------- 6 * 功能和描述: 7 **/ 8 9 public class Client { 10 public static void main(String[] args) { 11 //定义一个真实角色 12 Host host = new Host(); 13 //定义代理角色 14 Proxy proxy = new Proxy(host); 15 //使用代理角色的实例去实现具体操作 16 proxy.rent(); 17 } 18 }
静态代理总结
优点:
使真实角色处理的业务更加的纯粹,不再关注一些公共的事;
公共的业务由代理来完成,实现了业务的分工;
公共业务的扩展变得更加集中和方便
缺点:
类变多了,多了代理类,工作量变大了,且不易扩展
解决此问题的方案就是使用动态代理
2、动态代理
还是以租房子为例,因为在学习阶段,越是简单的例子越是容易理解,博主在学习的时候看到了好几篇文章光看代码就晕头转向的了,还没学习动态代理就已经蒙了。所以我这边举得例子基本都是大家常见的,代码简单,但是能将知识点介绍的很透彻。
动态代理有两种实现方式:一种是基于jdk的动态代理,一种是基于cglib的动态代理
基于jdk的动态代理
基于jdk的动态代理的特点是必须要有接口,记住一个类Proxy(java.lang.reflect.Proxy,别导错包)和一个接口InvocationHandler,废话少说,直接上代码
第一步:新建一个接口Rent
1 public interface Rent { 2 void rent(); 3 }
第二步:新建一个类(Host),实现该接口(Rent)
1 public class Host implements Rent{ 2 public void rent(){ 3 System.out.println("房屋出租"); 4 } 5 }
第三步:新建一个代理类,实现InvocationHandler接口
1 public class RentInvocationHandler implements InvocationHandler { 2 3 private Object object; 4 5 public RentInvocationHandler(Object object) { 6 this.object = object; 7 } 8 9 /** 10 * @param proxy:代理类 11 * @param method:代理类调用处理程序的方法对象 12 * @param args:方法的参数 13 */ 14 @Override 15 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 16 System.out.println("使用动态代理做的一些增强的操作......"); 17 //第一个参数表示真实对象 18 //第二个参数表示参数 19 Object result = method.invoke(object, args); 20 21 return result; 22 } 23 }
完工就是这么easy,下面开始测试
1 public class Client { 2 public static void main(String[] args) { 3 //定义一个真实对象 4 Host host = new Host(); 5 //创建代理类 6 RentInvocationHandler pih = new RentInvocationHandler(host); 7 //利用Proxy.newProxyInstance生成代理类 8 //第一个参数:真实类对象的类加载器 9 //第二个参数:真实类对象的所有的接口 10 //第三个参数:代理类对象 11 Rent p = (Rent)Proxy.newProxyInstance(host.getClass().getClassLoader(),host.getClass().getInterfaces(),pih); 12 p.rent(); 13 14 } 15 }
输出:
再次强调一点:在调用的时候
Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
只要搞清楚这里面的三个参数是干嘛的就OK
基于CGLib的动态代理
基于CGLib的动态代理是没有接口的限制的,行了,直接撸代码(虽然有重复的代码,但是为了让读者能够看的清晰,每一步我都会写出来)
第一步:创建一类真实类Host_CGLib
<dependency>
<groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>2.2.2</version> </dependency>
1 public class Host_CGLib { 2 public void rent(){ 3 System.out.println("租房子......CGLib"); 4 } 5 }
第二步:创建一个拦截器类实现MethodInterceptor(net.sf.cglib.proxy.MethodInterceptor)接口
1 public class RentMethodInterceptor implements MethodInterceptor { 2 @Override 3 public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { 4 System.out.println("使用CGLib方式做的增强......"); 5 Object result = methodProxy.invokeSuper(o, objects); 6 return result; 7 } 8 }
OK搞定,开始测试
1 public class CGLibTest { 2 public static void main(String[] args) { 3 //设置增强需要用到的类 4 Enhancer enhancer = new Enhancer(); 5 //设置需要增强的类(这里是Host_CGLib类) 6 enhancer.setSuperclass(Host_CGLib.class); 7 //设置需要回调的拦截器 8 enhancer.setCallback(new RentMethodInterceptor()); 9 //生成对应的增强类 10 Host_CGLib host = (Host_CGLib)enhancer.create(); 11 host.rent(); 12 } 13 }
输出:
总结:对于底层和原理这边并没有介绍,至于为什么没有介绍(因为我也不会),因为初学者先知道怎么用就行,不是什么东西都是刨根问底的,现在知道是什么,再是搞为什么吧。熟悉了以后在此基础上去深挖,这才是王道。 如果您觉得我写的文章您看明白了,请动动您的小手,将文章分享给您的好友哦!