萤火小屋

优律的知识库

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

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

jdk动态代理

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

简介

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

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
  • 文章目录
  • 站点概览
优律

优律

优律的知识库

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