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

SpringBoot选择CGLIB作为默认动态代理

Spring Boot从2.x版本开始,默认使用CGLIB作为动态代理实现。这是因为在Spring Boot 2.x中,为了解决使用JDK动态代理可能导致的类型转换异常问题,选择了CGLIB作为默认的代理方式。

Spring Boot项目代码示例,展示了如何使用CGLIB和JDK动态代理。

效果展示

项目结构

cglib-learn
├─src                     
│   ├─main                
│   │  ├─java             
│   │  │  └─com           
│   │  │      └─tyron
│   │  │          └─cgliblearn
│   │  │               ├─ CglibLearnApplication.java
│   │  │               ├─ aspect
│   │  │               │    └── LoggingAspect.java
│   │  │               ├─ config
│   │  │               │    └── AppConfig.java
│   │  │     		       └── service
│   │  │                 	  ├── UserService.java
│   │  │                    └── UserServiceInterface.java			
│   │  └── resources
│   │       └── application.properties
└── pom.xml

1、cglib代理

1.1、 pom.xml

确保您的项目包含 Spring Boot 和 AspectJ 依赖:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.5.4</version></parent><groupId>com.tyron</groupId><artifactId>cglib-learn</artifactId><version>0.0.1-SNAPSHOT</version><name>cglib-learn</name><description>cglib-learn</description><url/><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency></dependencies>
</project>

1.2、 CglibLearnApplication.java

package com.tyron.cgliblearn;import com.tyron.cgliblearn.service.UserService;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;@SpringBootApplication
public class CglibLearnApplication {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(CglibLearnApplication.class, args);// 使用cglib代理UserService userService = context.getBean(UserService.class);// 使用jdk代理//  UserServiceInterface userService = context.getBean(UserServiceInterface.class);System.out.println("Proxy class: " + userService.getClass());userService.sayHello();}
}

1.3、 UserService.java

package com.tyron.cgliblearn.service;import org.springframework.stereotype.Service;@Service
public class UserService {public void sayHello() {System.out.println("Hello, World!");}
}

1.4、 LoggingAspect.java

package com.tyron.cgliblearn.aspect;import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;@Aspect
@Component
public class LoggingAspect {@Before("execution(* com.tyron.cgliblearn.service.*.*(..))")public void logBefore() {System.out.println("Method is about to be called.");}
}

1.5、运行项目(cglib代理)

下图打印中可看出,在SpringBoot 2.5.4 版本中,默认使用 cglib 动态代理,后面我们再尝试使用jdk动态代理。

2、jdk代理

2.1、application.properties

application.properties中配置使用JDK动态代理

spring.aop.proxy-target-class=false

2.2、UserServiceInterface.java

如果希望使用JDK动态代理,可以创建一个接口和实现类:

package com.tyron.cgliblearn.service;public interface UserServiceInterface {public void sayHello();
}

2.3、UserServiceImpl.java

package com.tyron.cgliblearn.service;import org.springframework.stereotype.Service;@Service
public class UserServiceImpl implements UserServiceInterface {@Overridepublic void sayHello() {System.out.println("Hello, World!");}
}

2.4、运行项目(jdk代理)

3、cglib代理和jdk代理的区别

在Spring Boot中,CGLIB代理和JDK代理的主要区别在于它们的实现方式和适用场景。以下是两者的详细对比:

特性CGLIB代理JDK代理
实现方式通过生成目标类的子类来创建代理对象通过实现目标类的接口来创建代理对象
适用场景可以代理没有实现接口的类只能代理实现了接口的类
性能通常比JDK代理快,因为它使用了FastClass机制可能稍慢一些,因为它依赖于反射
限制不能代理final类或final方法不能代理没有接口的类
默认配置Spring Boot默认使用CGLIB代理需要显式配置使用JDK代理

为什么Spring Boot默认使用CGLIB代理?

Spring Boot默认使用CGLIB代理是因为CGLIB提供了更广泛的代理支持,可以代理没有实现接口的类。这对于提供更灵活的AOP配置和更高的性能是有益的。此外,CGLIB代理在某些情况下可能比JDK代理更快,因为它使用了FastClass机制来直接调用目标类的方法,而不是使用反射****

实际应用中的优缺点

  • CGLIB代理的优点:可以代理没有实现接口的类,通常性能更好。
  • CGLIB代理的缺点:不能代理final类或final方法,可能需要额外的配置来启用。
  • JDK代理的优点:最小化依赖关系,减少依赖意味着简化开发和维护
  • JDK代理的缺点:只能代理实现了接口的类,可能性能稍逊于CGLIB代理。

总结

在选择CGLIB代理还是JDK代理时,你需要考虑目标类是否实现了接口,以及你对性能的要求。如果你的应用程序中的类没有实现接口,或者你需要更高的性能,那么CGLIB代理可能是更好的选择。如果你的应用程序中的类已经实现了接口,或者你更倾向于使用JDK提供的功能,那么JDK代理可能更适合你。


http://www.mrgr.cn/news/81338.html

相关文章:

  • Kibana8.17.0在mac上的安装
  • openssl交叉编译(这次基本上正规了)
  • 汇总贴:cocos creator
  • 第22天:信息收集-Web应用各语言框架安全组件联动系统数据特征人工分析识别项目
  • YOLOv9-0.1部分代码阅读笔记-loss_tal_triple.py
  • 十二月第21讲:Java调用与发布Webservice接口
  • C语言结构体详细讲解
  • gateway网关
  • C语言项目 天天酷跑(上篇)
  • Pytorch分布式训练
  • Unity模型观察脚本
  • Android开发环境搭建和编译系统
  • 知识图谱嵌入大总结:难点、方法、工具、和图嵌入的区别
  • 【innodb 阅读笔记】之 数据页结构介绍
  • springboot容器无法获取@Autowired对象,报null对象空指针问题的解决方式
  • Element-plus表格使用总结
  • 5、mysql的读写分离
  • Docker数据库的主从复制
  • 基于springboot的海洋知识服务平台的设计与实现
  • HuaWei、NVIDIA 数据中心 AI 算力对比
  • ThinkPHP接入PayPal支付
  • Kibana:LINUX_X86_64 和 DEB_X86_64两种可选下载方式的区别
  • RT-DETR学习笔记(2)
  • CTFHub disable_functions通关
  • 华为路由器AR101W-S
  • go语言并发文件备份,自动比对自动重命名(逐行注释)