首页 > 编程语言 >Java代理模式

Java代理模式

时间:2023-06-17 12:33:25浏览次数:31  
标签:Java invoke Object 代理 模式 InvocationHandler 方法 public

一、基本概念

1、代理模式:使用代理对象来代替目标对象的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。

2、有静态代理和动态代理两种实现方式

 

二、静态代理

  • 静态代理是在编译时期就已经确定代理类的代码,在程序运行前就已经存在。
  • 静态代理需要为每个被代理的类创建一个代理类,代理类与被代理类实现相同的接口或继承相同的父类。
  • 静态代理的修改或增加功能需要修改代理类的代码,因此代码维护较为繁琐。

 

静态代理实现步骤:

  1. 定义一个接口及其实现类;
  2. 创建一个代理类同样实现这个接口
  3. 将目标对象注入进代理类,然后在代理类的对应方法调用目标类中的对应方法。这样的话,我们就可以通过代理类屏蔽对目标对象的访问,并且可以在目标方法执行前后做一些自己想做的事情。
 

二、动态代理

  • 动态代理是在运行时通过反射等机制动态生成代理类的代码,无需在编译时期就确定代理类。
  • 动态代理不需要为每个被代理类都创建一个代理类,代理逻辑可以统一处理,减少了代码的冗余。
  • 动态代理的修改或增加功能只需要调整代理逻辑,不需要修改代理类的代码,更加灵活。

在 Java 动态代理机制中 InvocationHandler 接口和 Proxy 类是核心。

Proxy 类中使用频率最高的方法是:newProxyInstance() ,这个方法主要用来生成一个代理对象。

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

  

这个方法一共有 3 个参数:

  1. loader :类加载器,用于加载代理对象。
  2. interfaces : 被代理类实现的一些接口;
  3. h : 实现了 InvocationHandler 接口的对象;

要实现动态代理的话,还必须需要实现InvocationHandler 来自定义处理逻辑。 当我们的动态代理对象调用一个方法时,这个方法的调用就会被转发到实现InvocationHandler 接口类的 invoke 方法来调用。

public interface InvocationHandler {

    /**
     * 当你使用代理对象调用方法的时候实际会调用到这个方法
     */
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

  

invoke() 方法有下面三个参数:

  1. proxy :动态生成的代理类
  2. method : 与代理类对象调用的方法相对应
  3. args : 当前 method 方法的参数

也就是说:你通过Proxy 类的 newProxyInstance() 创建的代理对象在调用方法的时候,实际会调用到实现InvocationHandler 接口的类的 invoke()方法。 你可以在 invoke() 方法中自定义处理逻辑,比如在方法执行前后做什么事情

动态代理实现步骤:
  • 定义一个接口及其实现类;
  • 自定义 InvocationHandler 并重写invoke方法,在 invoke 方法中我们会调用原生方法(被代理类的方法)并自定义一些处理逻辑;
  • 通过 Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) 方法创建代理对象;
1、定义发送短信的接口
public interface SmsService {
    String send(String message);
}

  

2、实现发送短信的接口

public class SmsServiceImpl implements SmsService {
    public String send(String message) {
        System.out.println("send message:" + message);
        return message;
    }
}

  

3、定义一个动态代理类,并重写invoke()方法

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @author shuang.kou
 * @createTime 2020年05月11日 11:23:00
 */
public class DebugInvocationHandler implements InvocationHandler {
    /**
     * 代理类中的真实对象
     */
    private final Object target;

    public DebugInvocationHandler(Object target) {
        this.target = target;
    }


    public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
        //调用方法之前,我们可以添加自己的操作
        System.out.println("before method " + method.getName());
        Object result = method.invoke(target, args);
        //调用方法之后,我们同样可以添加自己的操作
        System.out.println("after method " + method.getName());
        return result;
    }
}

  invoke() 方法: 当我们的动态代理对象调用原生方法的时候,最终实际上调用到的是 invoke() 方法,然后 invoke() 方法代替我们去调用了被代理对象的原生方法。

4、获取代理对象的工厂类

public class JdkProxyFactory {
    public static Object getProxy(Object target) {
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(), // 目标类的类加载
                target.getClass().getInterfaces(),  // 代理需要实现的接口,可指定多个
                new DebugInvocationHandler(target)   // 代理对象对应的自定义 InvocationHandler
        );
    }
}

  5.实际使用

SmsService smsService = (SmsService) JdkProxyFactory.getProxy(new SmsServiceImpl());
smsService.send("java");

  

标签:Java,invoke,Object,代理,模式,InvocationHandler,方法,public
From: https://www.cnblogs.com/coooookie/p/17487349.html

相关文章

  • Java序列化
    一、序列化和反序列化序列化:将数据结构或对象转换成二进制字节流的过程反序列化:将在序列化过程中产生的二进制字节流转换成数据结构或对象的过程 常见场景:1、网络传输时,对象需要先被序列化,接收到后再进行反序列化2、将对象持久化到磁盘、文件时需要先进行序列化,从磁盘或者......
  • Java线程池与异常处理
    线程池线程池的创建代码ThreadPoolExecutorthreadPoolExecutor=newThreadPoolExecutor(intcorePoolSize,intmaximumPoolSize,longkeepAliveTime,TimeUnitunit,......
  • Java值传递
    一、形参&实参实参:实际传递给方法的参数形参:用于定义方法,接收实参,不需要有确定的值 二、值传递&引用传递值传递:方法接受的是实参值的拷贝,会创建副本引用传递:方法接收的是实参所引用对象在堆中的地址,不会创建副本,对形参的修改将影响到形参Java只有值传递  publicstati......
  • BTA16-ASEMI代理意法原装可控硅BTA16
    编辑:llBTA16-ASEMI代理意法原装可控硅BTA16型号:BTA41品牌:ST/意法封装:TO-220正向电流:16A反向电压:600V引脚数量:3类型:双向可控硅特性:双向可控硅、意法原装可控硅工作温度:-40°C~150°C封装尺寸:如图BTA16产品描述:BTA16、BTB16和T1610、T1635和T1650三端双向可控硅系列适用于通用电源交......
  • BTA16-ASEMI代理意法原装可控硅BTA16
    编辑:llBTA16-ASEMI代理意法原装可控硅BTA16型号:BTA41品牌:ST/意法封装:TO-220正向电流:16A反向电压:600V引脚数量:3类型:双向可控硅特性:双向可控硅、意法原装可控硅工作温度:-40°C~150°C封装尺寸:如图BTA16产品描述:BTA16、BTB16和T1610、T1635和T1650三端双向可控硅系列适......
  • JAVA集合
    一、集合框架概览Java集合也叫做容器,由两大接口派生而来,一个是collection接口,主要用于存放单一元素,另一个是map接口,用于存放键值对。collection有三个子接口:list、set、queue。相较于数组,Java集合的优势在于它们的大小可变、支持泛型、具有内建算法,比如add(),remove()等。 l......
  • java——微服务——spring cloud——Nacos——Nacos配置共享
       ......
  • java——微服务——spring cloud——Nacos——Nacos配置热更新
                                                          ......
  • 字符串的模式匹配算法
    一.模式匹配字符串的模式匹配算法是用来查找一个字符串中是否存在另一个指定的字符串(即模式)的算法。常见的模式匹配算法包括暴力匹配算法、KMP算法、Boyer-Moore算法和Rabin-Karp算法。暴力匹配算法:暴力匹配算法也称为朴素匹配算法,是最简单的一种字符串匹配算法。它从主串的第一个......
  • Java 命名规范
    包命名规范包(Package)的作用是将功能相似或相关的类或者接口进行分组管理,便于类的定位和查找,同时也可以使用包来避免类名的冲突和访问控制,使代码更容易维护。通常,包名使用小写英文字母进行命名,并使用“.”进行分割,每个被分割的单元只能包含一个名词。一般地,包命名常采用顶级域......