Spring AOP的核心原理和兩種實(shí)現(xiàn)方式全解析
在Spring框架的學(xué)習(xí)旅程中,AOP(面向切面編程)絕對(duì)是核心重點(diǎn)之一。它打破了傳統(tǒng)縱向編程的思維局限,通過(guò)橫向抽取機(jī)制解決了代碼冗余、耦合度高的痛點(diǎn)。本文將從AOP的概念引入出發(fā),層層拆解核心原理,再通過(guò)完整實(shí)戰(zhàn)案例覆蓋配置文件和注解兩種實(shí)現(xiàn)方式,幫你徹底掌握Spring AOP的應(yīng)用精髓。
一、為什么需要AOP?從登錄功能增強(qiáng)場(chǎng)景說(shuō)起
要理解AOP的價(jià)值,我們先從一個(gè)常見(jiàn)的業(yè)務(wù)場(chǎng)景切入——登錄功能的增強(qiáng)。在基礎(chǔ)的登錄功能實(shí)現(xiàn)中,核心邏輯是校驗(yàn)用戶賬號(hào)密碼的合法性,驗(yàn)證通過(guò)后即可完成登錄流程。
但隨著業(yè)務(wù)迭代,我們往往需要在登錄功能之上疊加新的需求,比如「權(quán)限校驗(yàn)」:不同角色的用戶登錄后能訪問(wèn)的資源不同,需要在登錄后額外判斷角色權(quán)限。此時(shí),我們有兩種實(shí)現(xiàn)思路:
- 直接修改登錄功能的源代碼,在原有邏輯中嵌入權(quán)限校驗(yàn)代碼;
- 不改動(dòng)原有登錄代碼,通過(guò)外部機(jī)制為登錄功能附加權(quán)限校驗(yàn)?zāi)芰Α?/li>
第一種方案看似直接,卻存在諸多問(wèn)題:一旦核心業(yè)務(wù)邏輯(如登錄)需要疊加多個(gè)增強(qiáng)功能(權(quán)限校驗(yàn)、日志記錄、緩存處理等),源代碼會(huì)變得臃腫不堪,后續(xù)維護(hù)難度劇增;同時(shí),這些增強(qiáng)功能在多個(gè)業(yè)務(wù)模塊中可能重復(fù)出現(xiàn),導(dǎo)致代碼冗余。
而第二種方案正是AOP的核心思想——在不修改原有業(yè)務(wù)代碼的前提下,對(duì)程序功能進(jìn)行增強(qiáng)。這種方式能實(shí)現(xiàn)業(yè)務(wù)邏輯與增強(qiáng)邏輯的解耦,讓代碼結(jié)構(gòu)更清晰、可維護(hù)性更強(qiáng)。
二、AOP核心概念深度拆解
2.1 什么是AOP?
AOP全稱為Aspect Oriented Programming,即面向切面編程。它并非一種具體的技術(shù),而是一種編程范式,隸屬于軟件工程范疇,指導(dǎo)開(kāi)發(fā)者如何更合理地組織程序結(jié)構(gòu)。
AOP的思想最早由AOP聯(lián)盟提出并制定了相關(guān)規(guī)范,Spring框架引入AOP思想時(shí)完全遵循該規(guī)范。其核心是通過(guò)預(yù)編譯或運(yùn)行期動(dòng)態(tài)代理技術(shù),實(shí)現(xiàn)程序功能的統(tǒng)一維護(hù)。
作為OOP(面向?qū)ο缶幊蹋┑难永m(xù),AOP彌補(bǔ)了OOP在橫向功能擴(kuò)展上的不足。OOP通過(guò)繼承和封裝實(shí)現(xiàn)縱向的功能復(fù)用,而AOP通過(guò)橫向抽取機(jī)制,將分散在各個(gè)業(yè)務(wù)模塊中的重復(fù)代碼(如事務(wù)管理、安全檢查、日志記錄、緩存處理等)抽取出來(lái),形成獨(dú)立的「切面」,再動(dòng)態(tài)植入到需要增強(qiáng)的業(yè)務(wù)方法中。
一句話總結(jié)AOP的價(jià)值:隔離業(yè)務(wù)邏輯與增強(qiáng)邏輯,降低耦合度,提高代碼可重用性和開(kāi)發(fā)效率。
2.2 AOP的核心優(yōu)勢(shì)
基于AOP的設(shè)計(jì)思想,其核心優(yōu)勢(shì)主要體現(xiàn)在三個(gè)方面:
- 減少重復(fù)代碼:將日志、權(quán)限、事務(wù)等通用增強(qiáng)邏輯抽取為切面,避免在多個(gè)業(yè)務(wù)模塊中重復(fù)編寫(xiě);
- 提升開(kāi)發(fā)效率:開(kāi)發(fā)者只需專注于核心業(yè)務(wù)邏輯的實(shí)現(xiàn),通用增強(qiáng)功能直接復(fù)用已有的切面,無(wú)需重復(fù)開(kāi)發(fā);
- 便于維護(hù):當(dāng)通用增強(qiáng)邏輯需要修改時(shí)(如日志格式調(diào)整),只需修改對(duì)應(yīng)的切面代碼,無(wú)需改動(dòng)所有業(yè)務(wù)模塊,維護(hù)成本大幅降低。
2.3 AOP底層實(shí)現(xiàn)原理
Spring AOP的底層依賴兩種動(dòng)態(tài)代理技術(shù)實(shí)現(xiàn),具體使用哪種技術(shù)取決于被增強(qiáng)的類是否實(shí)現(xiàn)接口:
1. JDK動(dòng)態(tài)代理
當(dāng)被增強(qiáng)的類實(shí)現(xiàn)了接口時(shí),Spring會(huì)采用JDK動(dòng)態(tài)代理技術(shù)生成代理對(duì)象,核心步驟如下:
- 為被代理類的接口生成代理類的字節(jié)碼文件;
- 通過(guò)類加載器(ClassLoader)將生成的字節(jié)碼文件加載到JVM中;
- 創(chuàng)建代理類的實(shí)例對(duì)象,當(dāng)調(diào)用代理對(duì)象的方法時(shí),會(huì)觸發(fā)增強(qiáng)邏輯的執(zhí)行,再調(diào)用目標(biāo)方法。
2. CGLIB動(dòng)態(tài)代理
當(dāng)被增強(qiáng)的類沒(méi)有實(shí)現(xiàn)任何接口時(shí),Spring會(huì)采用CGLIB動(dòng)態(tài)代理技術(shù)。其核心原理是生成被代理類的子類作為代理對(duì)象,通過(guò)重寫(xiě)父類的方法植入增強(qiáng)邏輯。由于是基于繼承實(shí)現(xiàn)的,被代理類不能是final修飾的(final類無(wú)法被繼承)。
三、Spring AOP實(shí)戰(zhàn):配置文件方式
Spring AOP的實(shí)現(xiàn)方式有兩種:配置文件方式(XML)和注解方式。我們先從配置文件方式入手,通過(guò)完整的實(shí)戰(zhàn)案例理解AOP的核心術(shù)語(yǔ)和實(shí)現(xiàn)流程。
3.1 先搞懂AOP的核心術(shù)語(yǔ)
在開(kāi)始實(shí)戰(zhàn)前,必須先明確AOP的幾個(gè)核心術(shù)語(yǔ),否則會(huì)對(duì)配置邏輯感到困惑:
- Joinpoint(連接點(diǎn)):類中可以被增強(qiáng)的所有方法都稱為連接點(diǎn)(即哪些方法有增強(qiáng)的可能性);
- Pointcut(切入點(diǎn)):從所有連接點(diǎn)中篩選出的、真正需要被增強(qiáng)的方法(即明確要對(duì)哪個(gè)方法進(jìn)行增強(qiáng));
- Advice(通知/增強(qiáng)):攔截到切入點(diǎn)方法后要執(zhí)行的邏輯(如權(quán)限校驗(yàn)、日志記錄等),根據(jù)執(zhí)行時(shí)機(jī)不同分為前置通知、后置通知、環(huán)繞通知、最終通知、異常通知;
- Aspect(切面):切入點(diǎn)和通知的結(jié)合體,是AOP核心邏輯的載體(即「對(duì)哪個(gè)方法」+「做什么增強(qiáng)」的組合)。
3.2 實(shí)戰(zhàn)準(zhǔn)備:環(huán)境搭建
本案例基于Maven構(gòu)建項(xiàng)目,首先需要引入相關(guān)依賴。Spring AOP的實(shí)現(xiàn)依賴Spring核心包、AOP聯(lián)盟規(guī)范包、AspectJ相關(guān)包(用于解析切入點(diǎn)表達(dá)式)等,具體依賴如下:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--AOP聯(lián)盟規(guī)范包-->
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<!--Spring Aspects包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!--AspectJ織入包(解析切入點(diǎn)表達(dá)式)-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.3</version>
</dependency>
</dependencies>3.3 實(shí)戰(zhàn)步驟:實(shí)現(xiàn)方法增強(qiáng)
步驟1:創(chuàng)建被增強(qiáng)的目標(biāo)類(核心業(yè)務(wù)類)
創(chuàng)建一個(gè)User類,包含add和update兩個(gè)核心業(yè)務(wù)方法,這兩個(gè)方法就是我們潛在的連接點(diǎn):
// 被增強(qiáng)的目標(biāo)類(核心業(yè)務(wù)類)
public class User {
// 連接點(diǎn)/切入點(diǎn)
public void add(){
System.out.println("add......");
}
public void update(){
System.out.println("update......");
}
}步驟2:將目標(biāo)類交給Spring管理
在Spring配置文件(applicationContext.xml)中配置目標(biāo)類的Bean:
<bean id="user" class="com.aopImpl.User"></bean>
步驟3:創(chuàng)建切面類(增強(qiáng)邏輯載體)
創(chuàng)建UserProxy類作為切面類,在其中定義增強(qiáng)邏輯(通知)。這里先實(shí)現(xiàn)一個(gè)前置通知(目標(biāo)方法執(zhí)行前執(zhí)行的增強(qiáng)邏輯):
// 切面類(包含增強(qiáng)邏輯)
public class UserProxy {
// 前置通知:目標(biāo)方法執(zhí)行前執(zhí)行
public void before(){
System.out.println("before.............");
}
}步驟4:將切面類交給Spring管理
在配置文件中配置切面類的Bean:
<bean id="userProxy" class="com.aopImpl.UserProxy"></bean>
步驟5:配置AOP(綁定切入點(diǎn)和通知)
在配置文件中通過(guò)<aop:config>標(biāo)簽完成切面的配置,核心是綁定切入點(diǎn)(要增強(qiáng)的方法)和通知(增強(qiáng)邏輯):
<!--AOP核心配置-->
<aop:config>
<!--配置切面:關(guān)聯(lián)切面類(ref指定切面Bean的id)-->
<aop:aspect ref="userProxy">
<!--配置前置通知:指定通知方法(method)和切入點(diǎn)(pointcut)-->
<!--pointcut屬性:通過(guò)切入點(diǎn)表達(dá)式指定要增強(qiáng)的方法-->
<aop:before method="before" pointcut="execution(public void com.aopImpl.User.add())"/>
</aop:aspect>
</aop:config>步驟6:編寫(xiě)測(cè)試類驗(yàn)證結(jié)果
通過(guò)Spring容器獲取目標(biāo)類的Bean,調(diào)用add方法,觀察是否執(zhí)行增強(qiáng)邏輯:
public class DemoTest {
@Test
public void aopTest1(){
// 加載Spring配置文件,初始化容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 從容器中獲取User對(duì)象(實(shí)際是Spring生成的代理對(duì)象)
User user = (User) applicationContext.getBean("user");
// 調(diào)用add方法
user.add();
}
}3.4 切入點(diǎn)表達(dá)式詳解
在AOP配置中,切入點(diǎn)表達(dá)式是核心,它的作用是精準(zhǔn)定位要增強(qiáng)的方法。切入點(diǎn)表達(dá)式的完整格式如下:
execution([修飾符] [返回值類型] [類全路徑] [方法名 ( [參數(shù)] )])
各部分說(shuō)明及使用規(guī)則:
- 修飾符:可選,如public、private等,可省略不寫(xiě);
- 返回值類型:必填,必須與目標(biāo)方法的返回值類型一致,可使用
*表示任意返回值類型; - 類全路徑:必填,即目標(biāo)類的包名+類名,可使用
*模糊匹配(如com.*.User表示com包下任意子包中的User類); - 方法名:必填,可使用
*表示任意方法; - 參數(shù):必填,無(wú)參數(shù)寫(xiě)
(),單個(gè)任意參數(shù)寫(xiě)( * ),任意個(gè)數(shù)、任意類型參數(shù)寫(xiě)(..)。
常用切入點(diǎn)表達(dá)式示例:
- 增強(qiáng)com.aopImpl.User類的add方法(無(wú)參數(shù)、返回值為void):
execution(void com.aopImpl.User.add()) - 增強(qiáng)com.aopImpl.User類的所有方法(任意返回值、任意參數(shù)):
execution(* com.aopImpl.User.*(..)) - 增強(qiáng)com包下所有子包中所有類的所有方法:
execution(* com.*.*.*(..)) - 增強(qiáng)所有ServiceImpl結(jié)尾的類的save方法(任意返回值、任意參數(shù)):
execution(* com.*.*ServiceImpl.save(..))
3.5 五種通知類型的實(shí)現(xiàn)
除了前置通知,Spring AOP還支持五種通知類型,分別對(duì)應(yīng)不同的執(zhí)行時(shí)機(jī)。下面我們?cè)赨serProxy切面類中補(bǔ)充所有通知類型的實(shí)現(xiàn),并完成配置:
1. 前置通知(@Before)
目標(biāo)方法執(zhí)行前執(zhí)行,已在上面的案例中實(shí)現(xiàn),配置方式:
<aop:before method="before" pointcut="execution(* com.*.User.add(..))"/>
2. 環(huán)繞通知(@Around)
目標(biāo)方法執(zhí)行前后都執(zhí)行,需要手動(dòng)調(diào)用ProceedingJoinPoint的proceed()方法觸發(fā)目標(biāo)方法執(zhí)行:
// 環(huán)繞通知
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("環(huán)繞通知-前置增強(qiáng).............");
// 手動(dòng)執(zhí)行目標(biāo)方法
proceedingJoinPoint.proceed();
System.out.println("環(huán)繞通知-后置增強(qiáng).............");
}配置方式:
<aop:around method="around" pointcut="execution(* com.*.User.add(..))"/>
3. 最終通知(@After)
目標(biāo)方法無(wú)論執(zhí)行成功還是失敗,都會(huì)執(zhí)行(類似try-catch中的finally塊):
// 最終通知
public void after() {
System.out.println("最終通知.............");
}配置方式:
<aop:after method="after" pointcut="execution(* com.*.User.add(..))"/>
4. 后置通知(@AfterReturning)
目標(biāo)方法執(zhí)行成功后才會(huì)執(zhí)行,若目標(biāo)方法拋出異常則不執(zhí)行:
// 后置通知
public void afterReturning() {
System.out.println("后置通知.............");
}配置方式:
<aop:after-returning method="afterReturning" pointcut="execution(* com.*.User.add(..))"/>
5. 異常通知(@AfterThrowing)
目標(biāo)方法執(zhí)行失?。⊕伋霎惓#r(shí)才會(huì)執(zhí)行:
// 異常通知
public void afterThrowing() {
System.out.println("異常通知.............");
}為了驗(yàn)證異常通知,需要修改目標(biāo)類的add方法,手動(dòng)拋出異常:
public void add(){
// 手動(dòng)制造異常
int a = 10 / 0;
System.out.println("add......");
}配置方式:
<aop:after-throwing method="afterThrowing" pointcut="execution(* com.*.User.add(..))"/>
四、Spring AOP實(shí)戰(zhàn):注解方式(更簡(jiǎn)潔高效)
配置文件方式的AOP雖然邏輯清晰,但配置項(xiàng)較多,對(duì)于復(fù)雜項(xiàng)目會(huì)顯得繁瑣。Spring提供了注解方式的AOP實(shí)現(xiàn),通過(guò)注解可以快速完成切面的配置,更符合現(xiàn)代開(kāi)發(fā)習(xí)慣。
4.1 注解方式核心步驟
步驟1:環(huán)境準(zhǔn)備
依賴與配置文件方式一致,無(wú)需額外引入依賴。
步驟2:開(kāi)啟注解掃描和AOP自動(dòng)代理
在Spring配置文件中添加注解掃描和AOP自動(dòng)代理的配置,開(kāi)啟注解驅(qū)動(dòng)的AOP功能:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--開(kāi)啟注解掃描:指定要掃描的包(com.aopImpl)-->
<context:component-scan base-package="com.aopImpl"></context:component-scan>
<!--開(kāi)啟AOP自動(dòng)代理:讓Spring自動(dòng)為切面類生成代理對(duì)象-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>步驟3:使用注解標(biāo)識(shí)目標(biāo)類和切面類
通過(guò)@Component注解將目標(biāo)類和切面類交給Spring管理,通過(guò)@Aspect注解標(biāo)識(shí)切面類:
// 目標(biāo)類:通過(guò)@Component交給Spring管理
@Component
public class User {
public void add(){
System.out.println("add......");
}
}
// 切面類:@Component交給Spring管理,@Aspect標(biāo)識(shí)為切面類
@Component
@Aspect
public class UserProxy {
// 增強(qiáng)邏輯將在下面通過(guò)注解配置
}步驟4:使用注解配置通知和切入點(diǎn)
Spring提供了對(duì)應(yīng)的注解來(lái)配置五種通知類型,注解的value屬性用于指定切入點(diǎn)表達(dá)式:
@Component
@Aspect
public class UserProxy {
// 1. 前置通知:@Before
@Before(value = "execution(* com.*.User.add(..))")
public void before(){
System.out.println("前置通知.............");
}
// 2. 環(huán)繞通知:@Around(需手動(dòng)調(diào)用proceed()執(zhí)行目標(biāo)方法)
@Around(value = "execution(* com.*.User.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("環(huán)繞通知-前置增強(qiáng).............");
// 執(zhí)行目標(biāo)方法
proceedingJoinPoint.proceed();
System.out.println("環(huán)繞通知-后置增強(qiáng).............");
}
// 3. 最終通知:@After
@After(value = "execution(* com.*.User.add(..))")
public void after() {
System.out.println("最終通知.............");
}
// 4. 異常通知:@AfterThrowing
@AfterThrowing(value = "execution(* com.*.User.add(..))")
public void afterThrowing() {
System.out.println("異常通知.............");
}
// 5. 后置通知:@AfterReturning
@AfterReturning(value = "execution(* com.*.User.add(..))")
public void afterReturning() {
System.out.println("后置通知.............");
}
}步驟5:編寫(xiě)測(cè)試類驗(yàn)證
測(cè)試類與配置文件方式一致,直接調(diào)用目標(biāo)方法即可:
public class DemoTest {
@Test
public void aopTest1(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) applicationContext.getBean("user");
user.add();
}
}運(yùn)行測(cè)試方法,控制臺(tái)會(huì)按照通知的執(zhí)行順序輸出對(duì)應(yīng)的增強(qiáng)邏輯,說(shuō)明注解方式的AOP配置生效。
五、總結(jié):兩種AOP實(shí)現(xiàn)方式對(duì)比與適用場(chǎng)景
通過(guò)本文的學(xué)習(xí),我們掌握了Spring AOP的核心原理和兩種實(shí)現(xiàn)方式,這里對(duì)兩種方式進(jìn)行對(duì)比,幫助你選擇合適的開(kāi)發(fā)方案:
- 配置文件方式:配置項(xiàng)清晰,易于理解和維護(hù),適合簡(jiǎn)單項(xiàng)目或?qū)ψ⒔獠皇煜さ拈_(kāi)發(fā)者;缺點(diǎn)是配置繁瑣,復(fù)雜項(xiàng)目中配置文件會(huì)過(guò)于龐大。
- 注解方式:配置簡(jiǎn)潔高效,減少了配置文件的冗余,適合復(fù)雜項(xiàng)目;缺點(diǎn)是注解分散在代碼中,對(duì)于不熟悉項(xiàng)目結(jié)構(gòu)的開(kāi)發(fā)者來(lái)說(shuō),定位切面邏輯可能需要花費(fèi)更多時(shí)間。
無(wú)論選擇哪種方式,核心都是理解AOP的「橫向抽取、解耦增強(qiáng)」思想。掌握AOP后,你可以輕松處理日志記錄、權(quán)限校驗(yàn)、事務(wù)管理等通用功能,大幅提升代碼質(zhì)量和開(kāi)發(fā)效率。
最后,建議大家多動(dòng)手實(shí)踐,通過(guò)修改切入點(diǎn)表達(dá)式、切換通知類型等方式,深入理解AOP的執(zhí)行邏輯,真正將知識(shí)轉(zhuǎn)化為實(shí)戰(zhàn)能力。
到此這篇關(guān)于Spring AOP的核心原理和兩種實(shí)現(xiàn)方式全解析的文章就介紹到這了,更多相關(guān)Spring AOP原理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java如何基于okhttp請(qǐng)求SSE接口流式返回詳解
對(duì)于流式返回,Spring Boot提供了兩種不同的方式,下面這篇文章主要給大家介紹了關(guān)于Java如何基于okhttp請(qǐng)求SSE接口流式返回的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-03-03
解決未解析的依賴項(xiàng):‘net.sf.json-lib:json-lib:jar:2.4‘問(wèn)題
這篇文章主要介紹了解決未解析的依賴項(xiàng):‘net.sf.json-lib:json-lib:jar:2.4‘問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-06-06
Java計(jì)算兩個(gè)漢字相似度的實(shí)現(xiàn)方法
有時(shí)候我們希望計(jì)算兩個(gè)漢字的相似度,比如文本的 OCR 等場(chǎng)景,用于識(shí)別糾正,本文給大家詳細(xì)介紹了Java計(jì)算兩個(gè)漢字相似度的實(shí)現(xiàn)方法,文中有詳細(xì)的實(shí)現(xiàn)代碼,需要的朋友可以參考下2023-11-11
JAVA?ImageIO.read方法報(bào)錯(cuò)/無(wú)效問(wèn)題及解決
這篇文章主要介紹了JAVA?ImageIO.read方法報(bào)錯(cuò)/無(wú)效問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11
SpringBoot如何根據(jù)用戶系統(tǒng)時(shí)區(qū)動(dòng)態(tài)展示時(shí)間
這篇文章主要介紹了SpringBoot如何根據(jù)用戶系統(tǒng)時(shí)區(qū)動(dòng)態(tài)展示時(shí)間,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-01-01
Java內(nèi)存區(qū)域與內(nèi)存溢出異常詳解
這篇文章主要介紹了Java內(nèi)存區(qū)域與內(nèi)存溢出異常詳解的相關(guān)資料,需要的朋友可以參考下2017-03-03
Java將String字符串帶括號(hào)轉(zhuǎn)成List的簡(jiǎn)單方法
Java中我們有時(shí)需要對(duì)現(xiàn)有的字符串進(jìn)行切割并轉(zhuǎn)化成一個(gè)List集合,這篇文章主要給大家介紹了關(guān)于Java將String字符串帶括號(hào)轉(zhuǎn)成List的簡(jiǎn)單方法,需要的朋友可以參考下2023-03-03
聊聊DecimalFormat的用法及各符號(hào)的意義
這篇文章主要介紹了DecimalFormat的用法及各符號(hào)的意義,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10
java: 程序包c(diǎn)om.fasterxml.jackson.annotation不存在的解決辦法
當(dāng)我們?cè)趯?dǎo)入程序之后,系統(tǒng)給出錯(cuò)誤提示:java: 程序包c(diǎn)om.fasterxml.jackson.annotation不存在,本文主要介紹了Java程序包不存在的三種解決方法,需要的朋友可以參考下2024-02-02
Netty框架實(shí)現(xiàn)TCP/IP通信的完美過(guò)程
這篇文章主要介紹了Netty框架實(shí)現(xiàn)TCP/IP通信,這里使用的是Springboot+Netty框架,使用maven搭建項(xiàng)目,需要的朋友可以參考下2021-07-07

