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 }
输出:

 

总结:对于底层和原理这边并没有介绍,至于为什么没有介绍(因为我也不会),因为初学者先知道怎么用就行,不是什么东西都是刨根问底的,现在知道是什么,再是搞为什么吧。熟悉了以后在此基础上去深挖,这才是王道。

如果您觉得我写的文章您看明白了,请动动您的小手,将文章分享给您的好友哦!

  

 
 
 
posted @ 2019-06-12 15:20  孤僻的小孩  阅读(3667)  评论(1编辑  收藏  举报