Java静态代理和动态代理详解

 更新时间:2024年11月01日 08:37:09   作者:louisgeek  
这篇文章主要介绍了Java静态代理和动态代理,本文通过代码示例给大家讲解的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下

Java 静态代理和动态代理

  • 代理模式主要有静态代理和动态代理两种实现方式

静态代理

  • 指程序在运行之前所需要的代理类就已经被创建好了
  • 通常情况下代理类、目标类都需要实现同一个接口
  • 代理类内部维护了目标类的引用,在不改变目标类的情况下通过代理类增加功能来扩展目标类的逻辑功能,真正的业务逻辑还是由目标类来实现,代理类只是调用目标类的相关方法,符合开闭原则
  • 一般需要为每个目标类都创建代理类和接口,可能导致类的数量大大增加
  • 通常情况下接口一旦修改,代理类和目标类都需要修改,代码耦合度较高

示例

接口

public interface ILogin {
    void doLogin();
}

目标类

public class UserLogin implements ILogin {
  @Override
  public void doLogin(){
      System.out.print("用户登录逻辑");
  }   
}

代理类

public class UserLoginProxy implements ILogin {
  private UserLogin mUserLogin;
  public UserLoginProxy() {
    mUserLogin = new UserLogin();
  }
  @Override
  public void doLogin(){
    //...
    System.out.print("登录前逻辑");
    //真正的业务逻辑还是由目标类来实现
    mUserLogin.doLogin();
    System.out.print("登录后逻辑");     
    //...
  }
}

使用

	public static void main(String[] args){
     //
     ILogin iLogin = new UserLoginProxy();
     iLogin.doLogin();
	}

动态代理

  • 动态代理指在程序运行时通过反射机制等技术动态创建出代理对象
  • 基于接口的动态代理,通常通过 java.lang.reflect.Proxy 类和 java.lang.reflect.InvocationHandler 接口实现动态代理
  • 基于类的动态代理,比如使用 CGLIB(Code Generation Library,一个强大的 Java 字节码生成库)
  • InvocationHandler 调用处理器,是一个接口,有个 invoke 方法
  • 通过使用 Proxy#newProxyInstance 来创建指定接口的代理实现类,当调用代理对象任何方法时都会调用 InvocationHandler#invoke 方法,可以在这个方法中拿到传入的参数,注解等
  • 只能实现基于接口的动态代理,因为 Java 是单继承的,它在动态生成 $ProxyX 代理类的时候已经继承 Proxy 类了
  • 可以减少类的数量,降低工作量,灵活性高,可以在运行时动态地为不同的委托类创建代理对象
  • 减少对业务接口的依赖,降低耦合,便于后期维护,可以用于实现 AOP 面向切面编程,比如在某个逻辑功能前后添加日志记录、监控性能和权限检查控制等操作
  • 由于因为使用了反射,所以会在运行时会消耗一定的性能
private InvocationHandler mInvocationHandler = new InvocationHandler() {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //target 是目标类对象
            Object result = method.invoke(target,args);
            //
            return result;
        }
    };
//方式1
//创建代理类的 Class 对象,参数 (ClassLoader 类加载器,Class<?>)
Class<?> proxyClass = Proxy.getProxyClass(Toast.class.getClassLoader(), Toast.class);
//通过反射实例化代理对象
Toast toastProxy = (Toast) proxyClass.getConstructor(InvocationHandler.class).newInstance(mInvocationHandler);
//方式2,是方法1的简化版,newProxyInstance 内部代码逻辑和方法1基本一致
//直接创建代理对象,参数 (ClassLoader 类加载器,Class<?>[],InvocationHandler)
Toast toastProxy2 = (Toast) Proxy.newProxyInstance(Toast.class.getClassLoader(),new Class<?>[]{Toast.class}, mInvocationHandler);

示例

接口

public interface ICalculator {
    int add(int a, int b);
    int minus(int a, int b);
}

目标类

public class Calculator implements ICalculator {
    @Override
    public int add(int a, int b) {
        return a + b;
    }
    @Override
    public int minus(int a, int b) {
        return a - b;
    }
}

动态代理的处理类

  public class CalculatorInvocationHandler implements InvocationHandler {
      private Object target;
      public CalculatorInvocationHandler(Object target) {
          this.target = target;
      }
      @Override
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
          // 在方法调用前可以添加一些逻辑
          Object result = method.invoke(target, args);
          // 在方法调用后也可以添加一些逻辑
          return result;
      }
  }

使用

//目标类
ICalculator calculator = new Calculator();
//代理类
ICalculator proxyCalculator = (ICalculator) Proxy.newProxyInstance(
        calculator.getClass().getClassLoader(),
        calculator.getClass().getInterfaces(),
        new CalculatorInvocationHandler(calculator)
);

到此这篇关于Java静态代理和动态代理详解的文章就介绍到这了,更多相关Java静态和动态代理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Spring的事务管理你了解吗

    Spring的事务管理你了解吗

    这篇文章主要为大家介绍了Spring的事务管理,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-01-01
  • Java如何使用elasticsearch进行模糊查询

    Java如何使用elasticsearch进行模糊查询

    这篇文章主要介绍了Java如何使用elasticsearch进行模糊查询,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-02-02
  • 深入探究SpringBoot拦截器的自定义设计与实现全攻略

    深入探究SpringBoot拦截器的自定义设计与实现全攻略

    拦截器是Spring框架提供的核心功能之⼀,主要用来拦截用户的请求,在指定方法前后,根据业务需要执行预先设定的代码,本文将给大家和大家一起深入探究SpringBoot拦截器的自定义设计与实现,需要的朋友可以参考下
    2024-05-05
  • Java中String对象的深入理解

    Java中String对象的深入理解

    String对象作为Java语言中重要的数据类型之一,是我们平时编码最常用的对象之一,因此也是内存中占据空间最大的一个对象,然而很多人对它是一知半解,今天我们就来好好聊一聊这个既熟悉又陌生的String,需要的朋友可以参考下
    2023-05-05
  • jsoup 框架的使用小结

    jsoup 框架的使用小结

    jsoup 是一款基于Java的HTML解析器,它提供了一套非常省力的API,不但能直接解析某个URL地址、HTML文本内容,而且还能通过类似于 DOM、CSS 或者jQuery的方法来操作数据,所以jsoup也可以被当做爬虫工具使用,这篇文章主要介绍了jsoup使用,需要的朋友可以参考下
    2023-04-04
  • 通过实例深入学习Java的Struts框架中的OGNL表达式使用

    通过实例深入学习Java的Struts框架中的OGNL表达式使用

    这篇文章主要通过实例介绍了Java的Strus框架中的OGNL表达式使用,Struts框架是Java的SSH三大web开发框架之一,需要的朋友可以参考下
    2015-11-11
  • java打印菱形及直角和等腰三角形的方法

    java打印菱形及直角和等腰三角形的方法

    用Java输出菱形本身是一个比较简单的问题,这是Java初学者都要编写的一个算法,下面这篇文章主要给大家介绍了关于java打印菱形及直角和等腰三角形的方法,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-05-05
  • 通过xml配置SpringMVC注解DispatcherServlet初始化过程解析

    通过xml配置SpringMVC注解DispatcherServlet初始化过程解析

    这篇文章主要为大家介绍了通过xml配置SpringMVC注解DispatcherServlet初始化过程解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-10-10
  • 使用spring aop 统一捕获异常和写日志的示例demo

    使用spring aop 统一捕获异常和写日志的示例demo

    本文通过一个小demo给大家介绍spring AOP 实现的异常捕获和日志的方法技巧,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2021-08-08
  • Java使用ant.jar执行SQL脚本文件的示例代码

    Java使用ant.jar执行SQL脚本文件的示例代码

    这篇文章主要介绍了Java使用ant.jar执行SQL脚本文件,文中通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2024-02-02

最新评论