老生常谈设计模式之动态代理

发布时间 - 2026-01-11 01:49:50    点击率:

一、动态代理概念

动态代理分为JDK动态代理和cglib动态代理两种方式。

jdk动态代理是由Java内部的反射机制来实现的,cglib动态代理底层则是借助asm来实现的。

总的来说,反射机制在生成类的过程中比较高效,而asm在生成类之后的相关执行过程中比较高效(可以通过将asm生成的类进行缓存,这样解决asm生成类过程低效问题)。

还有一点必须注意:jdk动态代理的应用前提,必须是目标类基于统一的接口。如果没有上述前提,jdk动态代理不能应用

由此可以看出,jdk动态代理有一定的局限性,cglib这种第三方类库实现的动态代理应用更加广泛,且在效率上更有优势。

二、JDK动态代理

以下代码使用代理模式实现一个大小写字符转换的功能。

定义接口和实现类:

ISomeService接口:

package com.ietree.basicskill.designpattern.dynamicproxy.jdk;

/**
 * 接口类
 * 
 * @author Root
 */
public interface ISomeService {
  
  String doFirst();
  
  void doSecond();
}

SomeServiceImpl实现类:

package com.ietree.basicskill.designpattern.dynamicproxy.jdk;

/**
 * 实现类
 * 
 * @author Root
 */
public class SomeServiceImpl implements ISomeService {

  @Override
  public String doFirst() {
    System.out.println("执行doFirst()...");
    String result = "abcde";
    return result;
  }

  @Override
  public void doSecond() {
    System.out.println("执行doSecond()...");
  }

}

JDK动态代理类:

package com.ietree.basicskill.designpattern.dynamicproxy.jdk;

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

public class Main {
  public static void main(String[] args) {

    final ISomeService target = new SomeServiceImpl();
    
    // 使用JDK的Proxy动态代理,要求目标类和代理类必须实现相同的接口,因为其底层的执行原理与静态代理的相同
    ISomeService service = (ISomeService) Proxy.newProxyInstance(
        // 目标类的类加载器
        target.getClass().getClassLoader(),
        // 目标类所实现的所有接口
        target.getClass().getInterfaces(), 
        new InvocationHandler() {
          // proxy:代理对象
          // method:目标方法
          // args:目标方法的参数列表
          @Override
          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // 调用目标方法
            Object result = method.invoke(target, args);
            if (result != null) {
              result = ((String) result).toUpperCase();
            }
            return result;
          }
        });
    String result = service.doFirst();
    System.out.println(result);

    service.doSecond();
  }
}

三、cglib动态代理

Cglib是一个优秀的动态代理框架,它的底层使用ASM在内存中动态的生成被代理类的子类,使用CGLIB即使代理类没有实现任何接口也可以实现动态代理功能。CGLIB具有简单易用,它的运行速度要远远快于JDK的Proxy动态代理:

CGLIB的核心类:

net.sf.cglib.proxy.Enhancer – 主要的增强类

net.sf.cglib.proxy.MethodInterceptor – 主要的方法拦截类,它是Callback接口的子接口,需要用户实现

net.sf.cglib.proxy.MethodProxy – JDK的java.lang.reflect.Method类的代理类,可以方便的实现对源对象方法的调用,如使用:

Object o = methodProxy.invokeSuper(proxy, args);//虽然第一个参数是被代理对象,也不会出现死循环的问题。

net.sf.cglib.proxy.MethodInterceptor接口是最通用的回调(callback)类型,它经常被基于代理的AOP用来实现拦截(intercept)方法的调用。这个接口只定义了一个方法

public Object intercept(Object object, java.lang.reflect.Method method, Object[] args, MethodProxy proxy) throws Throwable;

第一个参数是代理对像,第二和第三个参数分别是拦截的方法和方法的参数。原来的方法可能通过使用java.lang.reflect.Method对象的一般反射调用,或者使用 net.sf.cglib.proxy.MethodProxy对象调用。net.sf.cglib.proxy.MethodProxy通常被首选使用,因为它更快。

以下程序实现了大小写转换的功能:

实现类SomeService:

package com.ietree.basicskill.designpattern.dynamicproxy.cglib;

/**
 * 实现类
 * 
 * @author Root
 */
public class SomeService {

  public String doFirst() {
    System.out.println("执行doFirst()...");
    String result = "abcde";
    return result;
  }

  public void doSecond() {
    System.out.println("执行doSecond()...");
  }

}

代理类MyCglibFactory:

package com.ietree.basicskill.designpattern.dynamicproxy.cglib;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class MyCglibFactory implements MethodInterceptor {

  private SomeService target;
  
  public MyCglibFactory() {
    super();
    target = new SomeService();
  }

  public SomeService myCglibCreator() {
    // 创建增强器对象
    Enhancer enhancer = new Enhancer();
    // 指定目标类,即父类
    enhancer.setSuperclass(SomeService.class);
    // 设置回调接口对象
    enhancer.setCallback(this);

    return (SomeService) enhancer.create();
  }

  @Override
  public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
    // 调用目标方法
    Object result = method.invoke(target, args);
    if (result != null) {
      result = ((String) result).toUpperCase();
    }
    return result;
  }

}

测试:

package com.ietree.basicskill.designpattern.dynamicproxy.cglib;

public class Main {
  public static void main(String[] args) {

    SomeService service = new MyCglibFactory().myCglibCreator();
    
    String result = service.doFirst();
    System.out.println("result = " + result);

    service.doSecond();
  }
}

运行结果:

执行doFirst()...
result = ABCDE
执行doSecond()...

以上这篇老生常谈设计模式之动态代理就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。


# 设计模式之动态代理  # 详解java动态代理模式  # Java动态代理分析及简单实例  # java 代理模式及动态代理机制深入分析  # java 反射和动态代理详解及实例代码  # Java动态代理分析及理解  # java动态代理(jdk与cglib)详细解析  # 第一个  # 给大家  # 来实现  # 回调  # 过程中  # 是一个  # 子类  # 老生常谈  # 是由  # 则是  # 两种  # 有一定  # 它是  # 可以通过  # 希望能  # 更有  # 如果没有  # 为其  # 更快  # 因为它 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: Laravel如何使用Guzzle调用外部接口_Laravel发起HTTP请求与JSON数据解析【详解】  油猴 教程,油猴搜脚本为什么会网页无法显示?  ,在苏州找工作,上哪个网站比较好?  Java垃圾回收器的方法和原理总结  高端企业智能建站程序:SEO优化与响应式模板定制开发  Laravel Asset编译怎么配置_Laravel Vite前端构建工具使用  如何用wdcp快速搭建高效网站?  如何在万网自助建站平台快速创建网站?  phpredis提高消息队列的实时性方法(推荐)  Android自定义控件实现温度旋转按钮效果  如何在Ubuntu系统下快速搭建WordPress个人网站?  如何在云服务器上快速搭建个人网站?  国美网站制作流程,国美电器蒸汽鍋怎么用官方网站?  Laravel事件和监听器如何实现_Laravel Events & Listeners解耦应用的实战教程  Python面向对象测试方法_mock解析【教程】  HTML透明颜色代码在Angular里怎么设置_Angular透明颜色使用指南【详解】  Laravel Blade组件怎么用_Laravel可复用视图组件的创建与使用  Laravel 419 page expired怎么解决_Laravel CSRF令牌过期处理  php结合redis实现高并发下的抢购、秒杀功能的实例  非常酷的网站设计制作软件,酷培ai教育官方网站?  rsync同步时出现rsync: failed to set times on “xxxx”: Operation not permitted  如何基于云服务器快速搭建网站及云盘系统?  装修招标网站设计制作流程,装修招标流程?  Laravel PHP版本要求一览_Laravel各版本环境要求对照  如何实现建站之星域名转发设置?  HTML透明颜色代码怎么让图片透明_给img元素加透明色的技巧【方法】  PythonWeb开发入门教程_Flask快速构建Web应用  如何用PHP快速搭建高效网站?分步指南  Laravel模型事件有哪些_Laravel Model Event生命周期详解  Laravel怎么上传文件_Laravel图片上传及存储配置  微信小程序 canvas开发实例及注意事项  Laravel任务队列怎么用_Laravel Queues异步处理任务提升应用性能  Laravel如何自定义分页视图?(Pagination示例)  Laravel如何实现URL美化Slug功能_Laravel使用eloquent-sluggable生成别名【方法】  Laravel Seeder填充数据教程_Laravel模型工厂Factory使用  如何在Windows环境下新建FTP站点并设置权限?  高防服务器如何保障网站安全无虞?  Laravel Blade模板引擎语法_Laravel Blade布局继承用法  Laravel如何使用Facades(门面)及其工作原理_Laravel门面模式与底层机制  在线制作视频的网站有哪些,电脑如何制作视频短片?  使用spring连接及操作mongodb3.0实例  品牌网站制作公司有哪些,买正品品牌一般去哪个网站买?  android nfc常用标签读取总结  如何在建站宝盒中设置产品搜索功能?  如何用好域名打造高点击率的自主建站?  JavaScript如何实现类型判断_typeof和instanceof有什么区别  Swift中switch语句区间和元组模式匹配  微信小程序 wx.uploadFile无法上传解决办法  Laravel如何生成URL和重定向?(路由助手函数)  Laravel的辅助函数有哪些_Laravel常用Helpers函数提高开发效率