萤火小屋

优律的知识库

  • 首页
  • 归档
  • 分类
  • 标签
  • 留言
  • 关于

  • 搜索
双指针 力扣 动态代理 Git YAML SpringBoot SpringMVC 回溯算法 分治算法 归并排序 快排 手撕 事务 MySQL索引 MySQL 小技巧 Spring Framework Spring 动态规划 Linux Android 贪心算法 操作系统 进程调度模拟 IPv6 数据库 计算机组成原理 计算机基础 栈 Java 静态路由 路由器 交换机 数字通信 网络工程 计算机网络 Web http 大学学习技巧 程序设计 算法

jdk动态代理

发表于 2022-01-19 | 分类于 Java SE | 0 | 阅读次数 29

简介

代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。

jdk动态代理模型图

为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从而在设计上获得了更大的灵活性。Java 动态代理机制以巧妙的方式近乎完美地实践了代理模式的设计理念。

jdk动态代理

java.lang.reflect.InvocationHandler接口中定义了一个invoke方法

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;

第一个参数proxy一般是指代理类,method是被代理的方法,args为该方法的参数数组。这个抽象方法在代理类中动态实现。

java.lang.reflect.Proxy代理类,通过以下方法生成一个代理类

@CallerSensitive
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException {...}

它返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)

所谓DynamicProxy是这样一种class:它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些 interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然,这个DynamicProxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。

在使用动态代理类时,我们必须实现InvocationHandler接口。

动态代理步骤

  1. 创建一个实现接口InvocationHandler的类,它必须实现invoke方法
  2. 创建被代理的类以及接口,被代理类实现该接口
  3. 通过Proxy的静态方法newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)创建一个代理类。
  4. 通过代理调用方法

示例

  1. 创建接口
public interface Subject {

    public String doSomething(String input);
    
}
  1. 创建被代理类并实现接口
public class SubjectImpl implements Subject {

    @Override
    public String doSomething(String input) {
        System.out.println("我是被代理类...");
        return input;
    }

}
  1. 创建InvocationHandler接口的实现类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class InvocationHandlerImpl implements InvocationHandler {

    /**
     * 被代理类对象
     */
    private Object subject;

    public InvocationHandlerImpl(Object subject) {
        this.subject = subject;
    }

    /**
     * @param proxy 代理类
     * @param method 被代理类的方法
     * @param args 被代理类方法的参数
     * @return 返回方法调用的结果
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        System.out.println("我是代理类对象通过InvocationHandler打印...before");

        // 通过反射调用被代理类的方法
        Object result = method.invoke(subject, args);

        System.out.println("我是代理类对象通过InvocationHandler打印...after");

        return result;
    }

}
  1. 创建一个测试的主类主方法
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class TestMain {

    public static void main(String[] args) {
        // 被代理类对象
        Subject subject = new SubjectImpl();
        // 创建一个InvocationHandler
        InvocationHandler handler = new InvocationHandlerImpl(subject);
        // 获得被代理类的类加载器
        ClassLoader loader = subject.getClass().getClassLoader();
        // 获得被代理类实现的接口
        Class[] interfaces = subject.getClass().getInterfaces();
        // 创建代理类
        Subject proxySubject = (Subject) Proxy.newProxyInstance(loader, interfaces, handler);
        // 打印代理类名字
        System.out.println("代理类的名字:" + proxySubject.getClass().getName());
        // 执行方法
        System.out.println(proxySubject.doSomething("我是输入的变量,将会被打印"));
    }

}
  1. 运行结果

image.png

参考文章

# Java # 动态代理
Spring的事务
Spring注解学习[email protected]和@Bean
  • 文章目录
  • 站点概览
优律

优律

优律的知识库

67 日志
17 分类
41 标签
E-mail Twitter Instagram
Links
  • CZLisyx - 浮生志
  • Vedfolnir
0%
© 2019 — 2022 萤火小屋——优律的博客网站
网站已勉强运行 
Halo博客系统技术支持