亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Spring?AOP概念及原理解析

 更新時(shí)間:2024年07月31日 08:58:08   作者:Si_wuxie  
這篇文章主要介紹了Spring?AOP概念及原理?,通過(guò)使用?Spring?AOP?實(shí)現(xiàn)日志管理,我們可以將日志記錄的邏輯從業(yè)務(wù)邏輯中分離出來(lái),簡(jiǎn)化了代碼的維護(hù),需要的朋友可以參考下

Spring AOP(面向切面編程)

以下內(nèi)容由ChatGPT生成

AOP(Aspect-Oriented Programming,面向切面編程)是一種編程范式,旨在通過(guò)分離關(guān)注點(diǎn)來(lái)提高程序的模塊化。Spring AOP 主要用于橫切關(guān)注點(diǎn)(如日志記錄、安全、事務(wù)管理等)的實(shí)現(xiàn)。在 Spring 中,AOP 的主要功能是為 Bean 增強(qiáng)功能,如添加額外的行為。

1. 靜態(tài)代理與動(dòng)態(tài)代理

靜態(tài)代理動(dòng)態(tài)代理是實(shí)現(xiàn) AOP 的兩種主要方式。

靜態(tài)代理

  • 在編譯時(shí)就已經(jīng)知道代理的目標(biāo)類,代理類在代碼中顯式地定義。
  • 靜態(tài)代理的缺點(diǎn)是需要為每個(gè)代理的類手動(dòng)編寫代理類,導(dǎo)致代碼冗余且難以維護(hù)。

動(dòng)態(tài)代理

  • 動(dòng)態(tài)代理是在運(yùn)行時(shí)生成代理類的,Java 中有兩種實(shí)現(xiàn)動(dòng)態(tài)代理的方式:JDK 動(dòng)態(tài)代理和 CGLIB
  • 動(dòng)態(tài)代理的優(yōu)點(diǎn)是可以為任意接口生成代理,不需要手動(dòng)編寫代理類。

JDK 動(dòng)態(tài)代理

  • JDK 動(dòng)態(tài)代理只代理實(shí)現(xiàn)了接口的類。它通過(guò) java.lang.reflect.Proxy 類和 java.lang.reflect.InvocationHandler 接口實(shí)現(xiàn)。
  • InvocationHandler 接口中定義了 invoke 方法,當(dāng)代理對(duì)象調(diào)用方法時(shí),會(huì)執(zhí)行該方法。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JdkProxyExample {
public static void main(String[] args) {
Foo foo = new FooImpl();
Foo proxyFoo = (Foo) Proxy.newProxyInstance(
Foo.class.getClassLoader(),
new Class<?>[]{Foo.class},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 前置增強(qiáng)
System.out.println("Before method: " + method.getName());
Object result = method.invoke(foo, args);
// 后置增強(qiáng)
System.out.println("After method: " + method.getName());
return result;
}
});
proxyFoo.doSomething();
}
}
interface Foo {
void doSomething();
}
class FooImpl implements Foo {
public void doSomething() {
System.out.println("Doing something...");
}
}

CGLIB 動(dòng)態(tài)代理

  • CGLIB 動(dòng)態(tài)代理通過(guò)生成目標(biāo)類的子類來(lái)實(shí)現(xiàn)代理,因此可以代理沒有接口的類。CGLIB 使用 ASM 字節(jié)碼操作庫(kù)來(lái)生成代理類。
  • CGLIB 的代理類重寫目標(biāo)類的方法,通過(guò)調(diào)用父類的 super 方法來(lái)實(shí)現(xiàn)對(duì)目標(biāo)方法的調(diào)用。
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class CglibProxyExample {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Foo.class);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// 前置增強(qiáng)
System.out.println("Before method: " + method.getName());
Object result = proxy.invokeSuper(obj, args);
// 后置增強(qiáng)
System.out.println("After method: " + method.getName());
return result;
}
});
Foo fooProxy = (Foo) enhancer.create();
fooProxy.doSomething();
}
}
class Foo {
public void doSomething() {
System.out.println("Doing something...");
}
}

2. Spring AOP 實(shí)現(xiàn)原理

Spring AOP 支持 JDK 動(dòng)態(tài)代理和 CGLIB 兩種代理機(jī)制。

  • JDK 動(dòng)態(tài)代理:當(dāng)目標(biāo)類實(shí)現(xiàn)了一個(gè)或多個(gè)接口時(shí),Spring 默認(rèn)使用 JDK 動(dòng)態(tài)代理來(lái)為目標(biāo)類創(chuàng)建代理對(duì)象。
  • CGLIB:如果目標(biāo)類沒有實(shí)現(xiàn)任何接口,Spring 則會(huì)使用 CGLIB 來(lái)生成目標(biāo)類的代理對(duì)象。

Spring 使用 AopProxy 接口和其兩個(gè)實(shí)現(xiàn)類 JdkDynamicAopProxy 和 CglibAopProxy 來(lái)分別處理這兩種代理機(jī)制。

Bean 被包裝成 Proxy

  • Spring 容器啟動(dòng)時(shí),解析配置文件或注解,生成 Bean 定義信息。
  • 在 Bean 初始化后,Spring AOP 的 BeanPostProcessor 之一(如 AbstractAutoProxyCreator 的子類)會(huì)檢查該 Bean 是否需要 AOP 增強(qiáng)。
  • 如果需要增強(qiáng),則會(huì)生成一個(gè)代理對(duì)象,替換掉原始的 Bean。這一過(guò)程是通過(guò)調(diào)用 getProxy() 方法來(lái)完成的。

創(chuàng)建 Proxy 對(duì)象

AopProxy 接口定義了 getProxy() 方法:

  • JdkDynamicAopProxy:通過(guò) JDK 動(dòng)態(tài)代理的 Proxy.newProxyInstance() 方法創(chuàng)建代理對(duì)象。
  • CglibAopProxy:通過(guò) CGLIB 的 Enhancer 類創(chuàng)建代理對(duì)象。

獲取代理對(duì)象

getProxy() 方法返回代理對(duì)象。代理對(duì)象的創(chuàng)建是在調(diào)用 getProxy() 方法時(shí)動(dòng)態(tài)生成的,并且在這個(gè)方法中處理了所有的 AOP 增強(qiáng)邏輯。

InvocationHandler 的實(shí)現(xiàn)

在 JDK 動(dòng)態(tài)代理中,InvocationHandler 的 invoke() 方法包含了攔截器鏈的邏輯。CglibAopProxy 通過(guò) Callback 和 MethodInterceptor 實(shí)現(xiàn)類似的功能。

public class MyInvocationHandler implements InvocationHandler {
private final Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 前置處理
System.out.println("Before method: " + method.getName());
// 調(diào)用目標(biāo)對(duì)象的方法
Object result = method.invoke(target, args);
// 后置處理
System.out.println("After method: " + method.getName());
return result;
}
}

在 invoke() 方法中:

  • 執(zhí)行前置增強(qiáng)邏輯。
  • 使用反射調(diào)用目標(biāo)對(duì)象的方法。
  • 執(zhí)行后置增強(qiáng)邏輯。

3. 攔截器鏈與方法鏈的執(zhí)行

Spring AOP 中的攔截器鏈?zhǔn)怯?nbsp;Advisor 和 MethodInterceptor 組成的。Advisor 包含切點(diǎn)(Pointcut)和通知(Advice),切點(diǎn)定義了哪些方法需要攔截,通知?jiǎng)t定義了攔截時(shí)執(zhí)行的邏輯。

在代理對(duì)象調(diào)用方法時(shí):

  • AopProxy 調(diào)用鏈會(huì)依次調(diào)用攔截器鏈中的攔截器。
  • 攔截器鏈通過(guò)責(zé)任鏈模式處理每一個(gè)攔截器。
  • 如果攔截器鏈中的某個(gè)攔截器決定執(zhí)行目標(biāo)方法,則會(huì)調(diào)用 MethodInvocation.proceed() 方法。
public class MyMethodInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
// 前置處理
System.out.println("Before method: " + invocation.getMethod().getName());
// 調(diào)用目標(biāo)對(duì)象的方法
Object result = invocation.proceed();
// 后置處理
System.out.println("After method: " + invocation.getMethod().getName());
return result;
}
}

在 invoke() 方法中,proceed() 方法用于繼續(xù)執(zhí)行下一個(gè)攔截器或目標(biāo)方法。如果沒有其他攔截器,則執(zhí)行目標(biāo)方法。

總結(jié)

Spring AOP 使用代理模式實(shí)現(xiàn)橫切關(guān)注點(diǎn)的管理,主要通過(guò) JDK 動(dòng)態(tài)代理和 CGLIB 動(dòng)態(tài)代理實(shí)現(xiàn)。代理對(duì)象是通過(guò) AopProxy 創(chuàng)建的,其中的 InvocationHandler 和 MethodInterceptor 負(fù)責(zé)執(zhí)行攔截器鏈的邏輯。Spring AOP 提供了強(qiáng)大的功能來(lái)增強(qiáng) Bean 的行為,使得切面邏輯與核心業(yè)務(wù)邏輯分離,提升了代碼的模塊化和可維護(hù)性。

以日志管理為例,Spring項(xiàng)目中如何使用AOP?

在 Spring 項(xiàng)目中使用 AOP 實(shí)現(xiàn)日志管理是一種常見的實(shí)踐。通過(guò) AOP,我們可以將日志記錄等橫切關(guān)注點(diǎn)與業(yè)務(wù)邏輯分離,使代碼更加清晰、模塊化。下面是一個(gè)使用 Spring AOP 實(shí)現(xiàn)日志管理的示例,包括如何定義切面、配置切面以及如何在應(yīng)用中使用它。

1. 引入依賴

首先,需要在項(xiàng)目中引入 Spring AOP 相關(guān)的依賴。如果使用的是 Maven,可以在 pom.xml 中添加以下依賴:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2. 定義切面(Aspect)

切面是包含橫切邏輯的類。在日志管理的示例中,我們將創(chuàng)建一個(gè)切面類來(lái)攔截方法調(diào)用并記錄日志。

package com.example.logging;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.JoinPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LoggingAspect {
    private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);
    // 定義切點(diǎn),攔截所有com.example.service包及其子包下的所有方法
    @Pointcut("execution(* com.example.service..*(..))")
    public void serviceMethods() {}
    // 方法執(zhí)行之前調(diào)用
    @Before("serviceMethods()")
    public void logBefore(JoinPoint joinPoint) {
        logger.info("Before method: " + joinPoint.getSignature().getName() + " - Arguments: " + joinPoint.getArgs());
    }
    // 方法正常返回之后調(diào)用
    @AfterReturning(pointcut = "serviceMethods()", returning = "result")
    public void logAfterReturning(JoinPoint joinPoint, Object result) {
        logger.info("After method: " + joinPoint.getSignature().getName() + " - Result: " + result);
    }
    // 方法拋出異常時(shí)調(diào)用
    @AfterThrowing(pointcut = "serviceMethods()", throwing = "error")
    public void logAfterThrowing(JoinPoint joinPoint, Throwable error) {
        logger.error("Exception in method: " + joinPoint.getSignature().getName() + " - Exception: " + error);
    }
}

3. 解釋切面中的注解和方法

  • @Aspect: 標(biāo)注該類為一個(gè)切面類。
  • @Component: 將該切面類作為 Spring 的 Bean 進(jìn)行管理。
  • @Pointcut: 定義一個(gè)切點(diǎn),execution(* com.example.service..*(..)) 表示匹配 com.example.service 包及其子包下的所有方法。
  • @Before: 表示在目標(biāo)方法執(zhí)行之前執(zhí)行 logBefore() 方法。
  • @AfterReturning: 表示在目標(biāo)方法正常返回之后執(zhí)行 logAfterReturning() 方法,其中 returning 屬性指定了返回值的變量名。
  • @AfterThrowing: 表示在目標(biāo)方法拋出異常時(shí)執(zhí)行 logAfterThrowing() 方法,其中 throwing 屬性指定了異常的變量名。

4. 配置切面掃描

確保 Spring 能夠掃描到定義的切面類。可以在主配置類(通常是啟動(dòng)類)中添加 @EnableAspectJAutoProxy 注解,啟用 AOP 功能:

package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@SpringBootApplication
@EnableAspectJAutoProxy
public class MyApp {
    public static void main(String[] args) {
        SpringApplication.run(MyApp.class, args);
    }
}

5. 使用日志管理的示例

假設(shè)有一個(gè)服務(wù)類 UserService,日志切面將記錄其方法調(diào)用:

package com.example.service;
import org.springframework.stereotype.Service;
@Service
public class UserService {
    public String getUserInfo(String userId) {
        // 模擬獲取用戶信息的操作
        return "User info for " + userId;
    }
    public void createUser(String userId, String name) {
        // 模擬創(chuàng)建用戶的操作
        System.out.println("User created: " + userId + ", " + name);
    }
}

在 UserService 的方法調(diào)用之前、正常返回之后,以及拋出異常時(shí),日志切面將分別記錄相關(guān)信息。

6. 總結(jié)

通過(guò)使用 Spring AOP 實(shí)現(xiàn)日志管理,我們可以將日志記錄的邏輯從業(yè)務(wù)邏輯中分離出來(lái),簡(jiǎn)化了代碼的維護(hù)。Spring AOP 提供了一種強(qiáng)大的方式來(lái)處理橫切關(guān)注點(diǎn),使得業(yè)務(wù)邏輯更為簡(jiǎn)潔和集中。

到此這篇關(guān)于Spring AOP概念及原理解析的文章就介紹到這了,更多相關(guān)Spring AOP原理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java的Atomic原子類詳解

    Java的Atomic原子類詳解

    這篇文章主要介紹了Java的Atomic原子類詳解,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-09-09
  • 劍指Offer之Java算法習(xí)題精講數(shù)組與字符串

    劍指Offer之Java算法習(xí)題精講數(shù)組與字符串

    跟著思路走,之后從簡(jiǎn)單題入手,反復(fù)去看,做過(guò)之后可能會(huì)忘記,之后再做一次,記不住就反復(fù)做,反復(fù)尋求思路和規(guī)律,慢慢積累就會(huì)發(fā)現(xiàn)質(zhì)的變化
    2022-03-03
  • Nacos?Discovery服務(wù)治理解決方案

    Nacos?Discovery服務(wù)治理解決方案

    DiscoveryClient是專門負(fù)責(zé)服務(wù)注冊(cè)和發(fā)現(xiàn)的,我們可以通過(guò)它獲取到注冊(cè)到注冊(cè)中心的所有服務(wù),這篇文章主要介紹了Nacos?Discovery服務(wù)治理,需要的朋友可以參考下
    2022-11-11
  • Java中的延遲隊(duì)列DelayQueue源碼解析

    Java中的延遲隊(duì)列DelayQueue源碼解析

    這篇文章主要介紹了Java中的延遲隊(duì)列DelayQueue源碼解析,DelayQueue是一個(gè)支持并發(fā)的無(wú)界延遲隊(duì)列,隊(duì)列中的每個(gè)元素都有個(gè)預(yù)定時(shí)間,當(dāng)線程從隊(duì)列獲取元素時(shí),只有到期元素才會(huì)出隊(duì)列,沒有到期元素則阻塞等待,需要的朋友可以參考下
    2023-12-12
  • 解決Springboot-application.properties中文亂碼問(wèn)題

    解決Springboot-application.properties中文亂碼問(wèn)題

    這篇文章主要介紹了解決Springboot-application.properties中文亂碼問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • 詳解Spring IOC 容器啟動(dòng)流程分析

    詳解Spring IOC 容器啟動(dòng)流程分析

    這篇文章主要介紹了Spring IOC 容器啟動(dòng)流程分析,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-08-08
  • mybatis-plus添加數(shù)據(jù)時(shí)id自增問(wèn)題及解決

    mybatis-plus添加數(shù)據(jù)時(shí)id自增問(wèn)題及解決

    這篇文章主要介紹了mybatis-plus添加數(shù)據(jù)時(shí)id自增問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • Java中Lambda表達(dá)式之Lambda語(yǔ)法與作用域解析

    Java中Lambda表達(dá)式之Lambda語(yǔ)法與作用域解析

    這篇文章主要介紹了Java中Lambda表達(dá)式之Lambda語(yǔ)法與作用域解析重點(diǎn)介紹Lambda表達(dá)式基礎(chǔ)知識(shí),需要的朋友可以參考下
    2017-02-02
  • 全面解析Java中的HashMap類

    全面解析Java中的HashMap類

    HashMap類為Java提供了鍵值對(duì)應(yīng)的map類型,本文將從源碼角度全面解析Java中的HashMap類,同時(shí)包括其各種常用操作方法等,歡迎參考與借鑒
    2016-05-05
  • 從Java到JSON一起探索Jackson的魔力

    從Java到JSON一起探索Jackson的魔力

    Jackson是一個(gè)用于處理JSON數(shù)據(jù)的開源Java庫(kù),這篇文章主要為大家介紹了Java是如何利用Jackson處理JSON數(shù)據(jù)的,感興趣的小伙伴可以了解一下
    2023-05-05

最新評(píng)論