代理模式——Java

代理模式

在Java中代理模式是一种设计模式,是通过代理类来代替原始的对象,可以在不改变原始对象的基础上,对它进行扩展(新增一些新功能)。在目标方法的执行的执行前后添加一些自定义的方法。

静态代理

步骤:

1.创建一个接口以及它的实现类

2.创建它的代理类实现该接口(重写接口中的方法,自定义一些新功能)

3.在代理类中注入目标类,并且调用代理类中的相关方法。

具体实现如下:

(1.)接口和其实现类

复制代码
public interface SsSercive {
    void say(String message);
}

实现类

复制代码
public class ImpService implements SsSercive {
    public void say(String message){
        System.out.println("信息:"+message);
    }
}

(2)代理类[也要实现该接口,并重写接口中的新方法,自定义新功能]

复制代码
public class ProxyImpl implements SsSercive {

    private final SsSercive service;
    //构造器
    public ProxyImpl(SsSercive service){
        this.service=service;
    }
    @Override
    public void say(String message) {
        System.out.println("操作前可以添加一些方法");
        service.say(message);
        System.out.println("操作后面也可以添加一些操作");
    }
}

(3)真正实现

复制代码
public class Main {
   public static void main(String[] args) {
   
        SsSercive service=new ImpService();
        //在代理类中调用目标类
       ProxyImpl proxy=new ProxyImpl(service);
       //调用代理类中的相关方法
        proxy.say("hello world");
   }
}

运行结果:

总结:

在静态代理中,对目标类的每个方法的增强都是手动的(因为代理类实现接口要重写各个方法),一个目标类对应一个代理类,因此十分不灵活,扩展性差。

从JVM角度来说,静态编译在接口中就将接口类、实现类、代理类转化成为class文件。

动态代理

动态代理不需要为每一个目标类创建一个代理类,也可以不实现接口(CGLIB动态代理不需要实现接口)。

从JVM角度来看,动态代理是在运行时生成类字节码,并且加载到JVM中。

JDK动态代理

JDK动态代理还是需要实现接口类Invocation,核心是Proxy代理类

(1.)接口类

复制代码
public interface SsSercive {
    void say(String message);
    void send(String name);
}

实现类

复制代码
public class ImpService implements SsSercive {
    @Override
    public void say(String message){
        System.out.println("信息:"+message);
    }
    @Override
    public void send(String name) {
        System.out.println("发送:"+name);
    }
}

(2)代理类

复制代码
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
//代理类实现InvocationHandler接口
public class DebugInvocationHandler implements InvocationHandler {
    private Object target;
    public DebugInvocationHandler(Object target){
        this.target=target;
    }
    @Override
    /*proxy:是动态代理生成的代理类
    method:调用的相关方法
    args:调用方法的相关参数
    */
    public Object invoke(Object proxy, Method method,Object[] args) throws InvocationTargetException, IllegalAccessException {
        System.out.println("方法之前可以添加一些功能:"+method.getName());
        //动态代理调用的是invoke方法,invoke方法代替我们去调用原方法
        Object result=method.invoke(target,args);
        System.out.println("方法之后可以添加一些功能:"+method.getName());
        return result;
    }
}

(3)代理对象的工厂类

复制代码
import java.lang.reflect.Proxy;
public class JdkProxyFactory {
//getProxy方法的本质是调用Proxy.newProxyInstance( ),获取某个类的代理对象
    public static Object getProxy(Object target){
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),//类加载器
                target.getClass().getInterfaces(),//代理对象实现的接口
                new DebugInvocationHandler(target)//自定义实现的Invocation接口
        );
    }
}

(4)实际使用

复制代码
public class Main {
    public static void main(String[] args) {

         SsSercive service=(SsSercive) JdkProxyFactory.getProxy(new ImpService());
         service.send("hello World");
         service.say("我是张三");
    }
}

(5)运行结果

CGLIB动态代理

(1)引入依赖

说明:Spring Boot 的 parent POM(如 spring-boot-starter-parent)已经为所有常用 Spring 模块定义好了兼容版本。显式指定版本可能导致找不到依赖或版本冲突,所以可以不用显示指定版本。

复制代码
<dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-core</artifactId>
      </dependency>

(2)目标类

复制代码
public class ImpService  {
  public void send(String name) {
      System.out.println("发送:"+name);
  }
}

(3)自定义方法拦截器

复制代码
mport org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class DebugMethodInterceptor implements MethodInterceptor {
  @Override
  public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
      //调用方法之前,我们可以添加自己的操作
      System.out.println("before method " + method.getName());
      Object object = methodProxy.invokeSuper(o, args);
      //调用方法之后,我们同样可以添加自己的操作
      System.out.println("after method " + method.getName());
      return object;
  }

}

(4)代理类

复制代码
import org.springframework.cglib.proxy.Enhancer;

public class CglibProxyFactory {
  public static Object getProxy(Class<?> clazz) {
      // 创建动态代理增强类
      Enhancer enhancer = new Enhancer();
      // 设置类加载器
      enhancer.setClassLoader(clazz.getClassLoader());
      // 设置被代理类
      enhancer.setSuperclass(clazz);
      // 设置方法拦截器
      enhancer.setCallback(new DebugMethodInterceptor());
      // 创建代理类
      return enhancer.create();

  }
}

(5)使用

复制代码
 public static void main(String[] args) {
      ImpService SmsService = (ImpService) CglibProxyFactory.getProxy(ImpService.class);
      SmsService.send("java");

(6)运行结果

JDK动态代理与CGLIB动态代理的区别

(1)JDK动态代理只能直接代理接口类或是代理实现接口的类,

CGLIB动态代理可以代理不实现任何接口的类。

(2)CGLIB在运行时生成代理类的子类,不需要通过实现接口,因此不能代理声明为final的类。

动态代理与静态代理的区别

(1)JVM角度:静态代理在编译时就将接口、实现类、代理类生成class文件,

而动态代理在运行时动态生成类字节码,并加载到jvm中。

(2)动态代理要比静态代理更加灵活,不用必须实现接口,可直接代理。不用针对每个目标类实现一个代理类。对于目标类中方法的改动,静态代理需要对代理类、目标对象进行修改,十分麻烦。

相关推荐
梦幻通灵12 分钟前
IDEA查看源码利器XCodeMap插件
java·intellij-idea
Ashlee_code23 分钟前
南太平洋金融基建革命:斐济-巴新交易所联盟的技术破局之路 ——从关税动荡到离岸红利,跨境科技如何重塑太平洋资本生态
java·开发语言·科技·金融·重构·web3·php
隐-梵24 分钟前
2025年测绘程序设计比赛--基于统计滤波的点云去噪(已获国特)
java·开发语言·windows·c#·.net
叉烧钵钵鸡1 小时前
Java ++i 与 i++ 底层原理
java·开发语言·后端
hqxstudying1 小时前
SpringAI的使用
java·开发语言·人工智能·springai
狐小粟同学1 小时前
JAVAEE--4.多线程案例
java·开发语言
the beard2 小时前
RabbitMQ:基于SpringAMQP声明队列与交换机并配置消息转换器(三)
java·开发语言·rabbitmq·intellij idea
大虾别跑2 小时前
tomcat隐藏400报错信息
java·安全·tomcat
曹朋羽2 小时前
spring mvc 整体处理流程原理
java·spring·mvc·spring mvc
蜗牛03142 小时前
2、RabbitMQ的5种模式基本使用(Maven项目)
java·springboot·java-rabbitmq