zoukankan      html  css  js  c++  java
  • 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 }
    输出:
    总结:对于底层和原理这边并没有介绍,至于为什么没有介绍(因为我也不会),因为初学者先知道怎么用就行,不是什么东西都是刨根问底的,现在知道是什么,再是搞为什么吧。熟悉了以后在此基础上去深挖,这才是王道。
    
    如果您觉得我写的文章您看明白了,请动动您的小手,将文章分享给您的好友哦!

      

     
     
     
  • 相关阅读:
    区间DP练习题题解
    【算法学习笔记】区间DP
    题解 CF1550C. Manhattan Subarrays (思维)
    【算法学习笔记】模运算总结
    题解 [HDU6747] Rotate 期望 + 逆元
    重新点亮linux 命令树————进程的控制[二十二]
    重新点亮linux 命令树————查看进程[二十一]
    docker 应用篇————日志、元数据、进程查看[五]
    docker 应用篇————docker基本命令[四]
    docker 应用篇————docker原理[三]
  • 原文地址:https://www.cnblogs.com/zyzblogs/p/11009872.html
Copyright © 2011-2022 走看看