zoukankan      html  css  js  c++  java
  • Java动态代理(一)

      好久没有动笔了,最近想巩固一下自己的基础知识,最近听到一同事问为什么JDK动态代理不能代理类,一听感觉懵逼呀!自己好像也不能很好的描述出来,所以想用2篇文章来复习一下动态代理知识;

    一、什么是静态代理?什么是动态代理?  

      静态代理:
        静态代理是在写代码中就把各个代理关系给理清了,在编译期就确定了类之间的关系;
      动态代理:
        在程序运行期间根据需要动态的创建代理类及其实例,来完成具体的功能;

    二、为什么要使用代理?  

      兄弟,你打方法的出入参的代码可以推一个房子了吧。使用代理可以将代码解耦,很多时候我们只要去关注我们最核心的实现,一些其他方面我可以交给代理去实现。最好的说明就是我们日常的AOP日志了,就是靠代理实现的。

    三、简单的代理实现  

      静态代理的简单实现代码参考我前面的代理模式的代码:
      今天我们先要写一下动态代理的简单代码:  

       InvocationHandler    

        InvocationHandler是JDK中提供的专门用于实现基于接口的动态代理的接口,主要用于进行方法调用模块,而代理类和实例的生成需要借助Proxy类完成。每个代理类的实例的调用处理器都是实现该接口实现的,而且是必备的,即每个动态代理实例的实现都必须拥有实现该接口的调用处理器,也可以这么说,每个动态代理实例都对应一个调用处理器。这里要区分两个概念,代理类和代理实例,调用处理器是在创建代理实例的时候才与其关联起来的,所以它与代理实例是一一对应的,而不是代理类。   

      Proxy    

        Proxy类是JDK提供的用于生成动态代理类和其实例的类。我们可以通过Proxy中的静态方法getProxyClass来生成代理类,需要的参数为类加载器和接口列表(数组),然后再通过反射调用代理类的构造器来生成代理实例,需要以一个InvocationHandler作为参数(体现出方法调用是与实例相关的,而非类)。
      了解了上面我们开始写代码实现:

      先写一个接口UserService,里面包含一个根据id查询用户名的方法,我们在这个查询方法的前后打印出出入参

     1 package com.roc.study.proxy;
     2 
     3 /**
     4  * <code>用户service</code>
     5  * <b>Note</b>
     6  *
     7  * @author liaowp
     8  * @see
     9  * @since 2018/5/14
    10  */
    11 
    12 public interface UserService {
    13 
    14     /**
    15      * 查询用户名称
    16      * @param id
    17      * @return
    18      */
    19     String getUserName(Integer id);
    20 
    21 }
     1 package com.roc.study.proxy;
     2 
     3 /**
     4  * <code>用户service实现类</code>
     5  * <b>Note</b>
     6  *
     7  * @author liaowp
     8  * @see
     9  * @since 2018/5/14
    10  */
    11 public class UserServiceImpl implements UserService {
    12 
    13     /**
    14      * 查询用户名称
    15      *
    16      * @return
    17      */
    18     @Override
    19     public String getUserName(Integer id) {
    20         System.out.println("liaowp");
    21         return "liaowp";
    22     }
    23 }
     1 package com.roc.study.proxy;
     2 
     3 import java.lang.reflect.InvocationHandler;
     4 import java.lang.reflect.Method;
     5 import java.lang.reflect.Proxy;
     6 
     7 /**
     8  * <code>用户代理类</code>
     9  * <b>Note</b>
    10  *
    11  * @author liaowp
    12  * @see
    13  * @since 2018/5/14
    14  */
    15 
    16 public class UserInvocationHandler implements InvocationHandler {
    17 
    18     private Object target;
    19 
    20     public UserInvocationHandler(Object target) {
    21         this.target = target;
    22     }
    23 
    24     /**
    25      * 在代理实例上处理方法调用并返回结果。
    26      * 当在与其关联的代理实例上调用方法时,将在调用处理程序上调用此方法。
    27      * @param proxy 我们所代理的那个真实对象
    28      * @param method 方法
    29      * @param args 入参
    30      * @return
    31      * @throws Throwable
    32      */
    33     @Override
    34     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    35         System.out.println("入参args->" + args);
    36         // 执行目标对象的方法
    37         Object result = method.invoke(target, args);
    38         System.out.println("出参args->"+result.toString());
    39         return result;
    40     }
    41 
    42     /**
    43      * 获取目标对象的代理对象
    44      * @return 代理对象
    45      */
    46     public Object getProxy() {
    47         return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
    48                 target.getClass().getInterfaces(), this);
    49     }
    50 
    51 }
    package com.roc.study.proxy;
    
    /**
     * <code>代理测试类</code>
     * <b>Note</b>
     *
     * @author liaowp
     * @see
     * @since 2018/5/14
     */
    public class ProxyTest {
    
        public static void main(String[] args) {
            UserService userService = new UserServiceImpl();
            UserInvocationHandler userInvocationHandler = new UserInvocationHandler(userService);
            // 根据目标对象生成代理对象
            UserService proxy = (UserService) userInvocationHandler.getProxy();
            // 调用代理对象的方法
            proxy.getUserName(1);
        }
    }

    运行结果:

    入参args->[Ljava.lang.Object;@5cad8086
    liaowp
    出参args->liaowp

    Process finished with exit code 0

  • 相关阅读:
    mysql and与or连用时遇到的坑
    mysql : 使用不等于过滤null的问题
    Bio Nio demo
    线上服务器的cpu使用达到100%了,如何排查、定位和解决该问题?
    二叉查找树、平衡二叉树、B树、B+树、聚集索引、非聚集索引
    java实现折线图统计数据
    递归构造树
    python中获取json数组中的具体数值(调用百度AI返回的json数据)
    python中使用ajax回调函数限制
    python+flask框架——前后端数据传递
  • 原文地址:https://www.cnblogs.com/liaoweipeng/p/9038030.html
Copyright © 2011-2022 走看看