当前位置: 首页 > news >正文

做火锅加盟哪个网站好主营商城网站建设

做火锅加盟哪个网站好,主营商城网站建设,量体定制,怎样建立微信公众号平台在 Spring 框架中,AOP(面向切面编程)是其核心特性之一,而实现 AOP 的关键在于代理机制。Spring 提供了两种主要的代理方式:JDK 动态代理和 CGLIB 代理。理解这两种代理方式的原理、优缺点及适用场景,对于深…

在 Spring 框架中,AOP(面向切面编程)是其核心特性之一,而实现 AOP 的关键在于代理机制。Spring 提供了两种主要的代理方式:JDK 动态代理和 CGLIB 代理。理解这两种代理方式的原理、优缺点及适用场景,对于深入掌握 Spring AOP 至关重要。本文将结合你的学习笔记,详细解析这两种代理机制,并通过代码示例和性能对比帮助你更好地理解和记忆。

一、JDK 动态代理:基于接口的代理实现

1. 核心原理

JDK 动态代理是 Java 原生提供的代理机制,其核心基于 Java 反射机制。它要求目标类必须实现至少一个接口,代理对象会实现相同的接口,从而在运行时动态拦截对目标方法的调用。

代理对象的生成过程主要涉及以下几个步骤:

  • 通过Proxy.getProxyClass()方法生成实现了目标接口的代理类字节码
  • 使用ClassLoader加载该字节码生成 Class 对象
  • 通过反射调用构造器创建代理实例

2. 代码实现示例

下面是一个使用 JDK 动态代理的简单示例:

// 定义业务接口
public interface UserService {void saveUser(String username);String getUserById(Long id);
}// 实现业务接口
public class UserServiceImpl implements UserService {@Overridepublic void saveUser(String username) {System.out.println("保存用户: " + username);}@Overridepublic String getUserById(Long id) {System.out.println("获取用户ID: " + id);return "用户" + id;}
}// 实现InvocationHandler接口,处理方法调用
public class JdkProxyHandler implements InvocationHandler {private final Object target; // 目标对象public JdkProxyHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 前置增强System.out.println("JDK动态代理: 方法调用前增强");// 调用目标方法Object result = method.invoke(target, args);// 后置增强System.out.println("JDK动态代理: 方法调用后增强");return result;}
}// 代理工厂类
public class JdkProxyFactory {public static Object getProxy(Object target) {return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),new JdkProxyHandler(target));}
}// 使用示例
public class JdkProxyExample {public static void main(String[] args) {UserService target = new UserServiceImpl();UserService proxy = (UserService) JdkProxyFactory.getProxy(target);proxy.saveUser("张三");proxy.getUserById(1L);}
}

3. 关键特性

  • 必须基于接口:代理对象实现了目标接口,而不是继承目标类
  • 反射调用:通过InvocationHandlerinvoke方法处理所有调用
  • 性能特点:首次生成代理类较快,但每次方法调用都需要通过反射,存在一定性能开销

二、CGLIB 代理:基于继承的代理实现

1. 核心原理

CGLIB(Code Generation Library)是一个强大的、高性能的代码生成库,Spring AOP 在 JDK 动态代理无法使用时会选择使用 CGLIB。CGLIB 通过继承目标类生成子类的方式实现代理,因此可以代理没有实现接口的类。

CGLIB 代理的生成过程主要涉及:

  • 使用 ASM 字节码生成框架动态生成目标类的子类
  • 重写父类的方法,在方法调用前后插入增强逻辑
  • 使用MethodInterceptor接口处理方法调用

2. 代码实现示例

下面是一个使用 CGLIB 代理的示例:

// 目标类(没有实现接口)
public class OrderService {public void createOrder(String orderNo) {System.out.println("创建订单: " + orderNo);}
}// 实现MethodInterceptor接口,处理方法调用
public class CglibInterceptor implements MethodInterceptor {@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {// 前置增强System.out.println("CGLIB代理: 方法调用前增强");// 调用目标方法(注意这里使用methodProxy.invokeSuper而不是method.invoke)Object result = proxy.invokeSuper(obj, args);// 后置增强System.out.println("CGLIB代理: 方法调用后增强");return result;}
}// 代理工厂类
public class CglibProxyFactory {public static <T> T getProxy(Class<T> targetClass) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(targetClass);enhancer.setCallback(new CglibInterceptor());return (T) enhancer.create();}
}// 使用示例
public class CglibProxyExample {public static void main(String[] args) {OrderService proxy = CglibProxyFactory.getProxy(OrderService.class);proxy.createOrder("ORD12345");}
}

3. 关键特性

  • 基于继承:代理对象继承自目标类,因此不能代理 final 类或方法
  • 字节码生成:使用 ASM 直接生成字节码,运行时不需要反射调用
  • 性能特点:首次生成代理类较慢(需要生成字节码并加载),但运行时性能较好

三、Spring 中的代理策略选择

Spring AOP 在选择代理方式时遵循以下策略:

  1. 默认优先使用 JDK 动态代理:如果目标对象实现了至少一个接口
  2. 自动切换到 CGLIB 代理:如果目标对象没有实现任何接口
  3. 强制使用 CGLIB 代理:可以通过配置proxy-target-class="true"@EnableAspectJAutoProxy(proxyTargetClass = true)

配置示例

// Java配置方式
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true) // 强制使用CGLIB代理
public class AppConfig {// 配置Bean和切面
}// XML配置方式
<aop:aspectj-autoproxy proxy-target-class="true"/>

四、性能对比与适用场景

1. 性能对比

  • 首次代理生成:JDK 动态代理较快(反射机制),CGLIB 较慢(需要生成字节码)
  • 方法调用:JDK 动态代理通过反射调用,性能稍低;CGLIB 直接调用,性能较高
  • 长期使用:如果代理对象需要被频繁调用,CGLIB 的总体性能更优

2. 适用场景

  • JDK 动态代理适用场景

    • 目标对象实现了接口
    • 代理对象主要用于接口方法的调用
    • 对首次代理生成速度有较高要求
  • CGLIB 代理适用场景

    • 目标对象是普通类(没有实现接口)
    • 需要代理类中的所有方法
    • 代理对象会被频繁调用,对运行时性能要求较高

五、特殊情况处理

1. 无法代理 final 类 / 方法

由于 CGLIB 通过继承实现代理,因此无法代理 final 类或 final 方法。如果尝试代理 final 类,Spring 会抛出AopConfigException

2. 混合使用接口和类

当一个类既实现了接口,又有一些非接口方法时,需要特别注意:

  • 如果使用 JDK 动态代理,只能代理接口中定义的方法
  • 如果使用 CGLIB 代理,可以代理所有方法(包括非接口方法)

3. 构造函数增强

CGLIB 支持对构造函数进行增强,而 JDK 动态代理只能对方法进行增强。

六、源码分析与理解

1. Spring 中的代理创建逻辑

Spring 在创建代理时主要通过ProxyFactory类实现,核心代码如下:

public class ProxyFactory extends ProxyCreatorSupport {public Object getProxy() {return createAopProxy().getProxy();}protected final synchronized AopProxy createAopProxy() {if (!this.active) {activate();}return getAopProxyFactory().createAopProxy(this);}
}

2. 代理方式选择源码

DefaultAopProxyFactory类负责根据条件选择代理方式:

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {@Overridepublic AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {Class<?> targetClass = config.getTargetClass();if (targetClass == null) {throw new AopConfigException("TargetSource cannot determine target class: " +"Either an interface or a target is required for proxy creation.");}// 如果目标类是接口或已经是JDK代理类,则使用JDK代理if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {return new JdkDynamicAopProxy(config);}// 否则使用CGLIB代理return new ObjenesisCglibAopProxy(config);}else {// 默认使用JDK代理return new JdkDynamicAopProxy(config);}}
}

七、总结与最佳实践

1. 核心要点总结

  • JDK 动态代理基于接口,CGLIB 基于继承
  • Spring 默认优先使用 JDK 动态代理,无法使用时切换到 CGLIB
  • 可以通过配置强制使用 CGLIB 代理
  • CGLIB 首次生成代理类较慢,但运行时性能更优

2. 最佳实践建议

  • 优先使用接口:设计类时尽量通过接口定义行为,便于使用 JDK 动态代理
  • 谨慎使用 final:避免将类或方法声明为 final,以免影响 CGLIB 代理
  • 性能敏感场景:如果代理对象会被频繁调用,考虑使用 CGLIB 并缓存代理实例
  • 调试与监控:在开发和测试阶段,注意观察代理方式的选择是否符合预期

通过深入理解 JDK 动态代理和 CGLIB 的原理与应用,我们可以更好地掌握 Spring AOP 的核心机制,在实际项目中做出更合适的技术选择,提高系统的可维护性和性能。

希望这篇博客能够帮助你更好地理解和记忆 Spring 代理机制的相关知识!如果有任何疑问或需要进一步探讨的地方,欢迎留言交流。

http://www.dtcms.com/a/422950.html

相关文章:

  • 网站维护怎么做wordpress主题无法预览
  • [吾爱大神原创] wx小程序自动解包工具界面版1.0.0
  • Datagrip连接Oracle23的一些异常记录
  • springboot+vue心理健康服务小程序(源码+文档+调试+基础修改+答疑)
  • flink api-datastream api-source算子
  • 基于数据挖掘的在线游戏行为分析预测系统
  • 无极领域付费网站做外贸要访问国外的网站怎么办
  • 本地项目上传到Git仓库
  • 首批CCF教学案例大赛资源上线:涵盖控制仿真、算法与机器人等9大方向
  • Java外功精要(2)——Spring IoCDI
  • Git简单理解
  • 机器人的“神经网络”:以太网技术如何重塑机器人内部通信?【技术类】
  • k8s-pod的资源限制
  • 【附源码】基于Vue的网上约课系统的设计与实现
  • 元宇宙的操作系统:虚拟世界的管理平台
  • 软考 系统架构设计师系列知识点之杂项集萃(161)
  • Python爬虫实战:获取中国检察网公开的案件信息与数据分析
  • 北大软件数字统战解决方案:用智能化技术破解基层治理难题、提升政务服务效能
  • Vue三元表达式
  • 吉林做网站公司wordpress手机仪表盘
  • seo案例网站建设哪家好WordPress用户名怎么泄露的
  • 狄利克雷先验:贝叶斯分析中的多面手与它的学术传承
  • 第三章、信息系统治理
  • 欧姆龙 CP1H PLC借助以太网通讯处理器实现在检测生产线上的应用案例
  • 【C++】继承:菱形继承
  • 【Rust GUI开发入门】编写一个本地音乐播放器(4. 绘制按钮组件)
  • Django小说个性化推荐系统 双算法(基于用户+物品) 评论收藏 书架管理 协同过滤推荐算法(源码+文档)✅
  • 微调数据格式详解:适配任务、模型与生态的最佳实践
  • 黑帽seo是什么做模板网站乐云seo效果好
  • 怎么编辑自己的网站企业展示型网站程序