欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring?AOP概念及原理解析

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

Spring AOP(面向切面編程)

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

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

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

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

靜態(tài)代理

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

動態(tài)代理

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

JDK 動態(tài)代理

  • JDK 動態(tài)代理只代理實現(xiàn)了接口的類。它通過 java.lang.reflect.Proxy 類和 java.lang.reflect.InvocationHandler 接口實現(xiàn)。
  • InvocationHandler 接口中定義了 invoke 方法,當(dāng)代理對象調(diào)用方法時,會執(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 {
// 前置增強
System.out.println("Before method: " + method.getName());
Object result = method.invoke(foo, args);
// 后置增強
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 動態(tài)代理

  • CGLIB 動態(tài)代理通過生成目標(biāo)類的子類來實現(xiàn)代理,因此可以代理沒有接口的類。CGLIB 使用 ASM 字節(jié)碼操作庫來生成代理類。
  • CGLIB 的代理類重寫目標(biāo)類的方法,通過調(diào)用父類的 super 方法來實現(xiàn)對目標(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 {
// 前置增強
System.out.println("Before method: " + method.getName());
Object result = proxy.invokeSuper(obj, args);
// 后置增強
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 實現(xiàn)原理

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

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

Spring 使用 AopProxy 接口和其兩個實現(xiàn)類 JdkDynamicAopProxy 和 CglibAopProxy 來分別處理這兩種代理機制。

Bean 被包裝成 Proxy

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

創(chuàng)建 Proxy 對象

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

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

獲取代理對象

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

InvocationHandler 的實現(xiàn)

在 JDK 動態(tài)代理中,InvocationHandler 的 invoke() 方法包含了攔截器鏈的邏輯。CglibAopProxy 通過 Callback 和 MethodInterceptor 實現(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)對象的方法
Object result = method.invoke(target, args);
// 后置處理
System.out.println("After method: " + method.getName());
return result;
}
}

在 invoke() 方法中:

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

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

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

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

  • AopProxy 調(diào)用鏈會依次調(diào)用攔截器鏈中的攔截器。
  • 攔截器鏈通過責(zé)任鏈模式處理每一個攔截器。
  • 如果攔截器鏈中的某個攔截器決定執(zhí)行目標(biāo)方法,則會調(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)對象的方法
Object result = invocation.proceed();
// 后置處理
System.out.println("After method: " + invocation.getMethod().getName());
return result;
}
}

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

總結(jié)

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

以日志管理為例,Spring項目中如何使用AOP?

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

1. 引入依賴

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

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

2. 定義切面(Aspect)

切面是包含橫切邏輯的類。在日志管理的示例中,我們將創(chuàng)建一個切面類來攔截方法調(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);
    // 定義切點,攔截所有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);
    }
    // 方法拋出異常時調(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)注該類為一個切面類。
  • @Component: 將該切面類作為 Spring 的 Bean 進行管理。
  • @Pointcut: 定義一個切點,execution(* com.example.service..*(..)) 表示匹配 com.example.service 包及其子包下的所有方法。
  • @Before: 表示在目標(biāo)方法執(zhí)行之前執(zhí)行 logBefore() 方法。
  • @AfterReturning: 表示在目標(biāo)方法正常返回之后執(zhí)行 logAfterReturning() 方法,其中 returning 屬性指定了返回值的變量名。
  • @AfterThrowing: 表示在目標(biāo)方法拋出異常時執(zhí)行 logAfterThrowing() 方法,其中 throwing 屬性指定了異常的變量名。

4. 配置切面掃描

確保 Spring 能夠掃描到定義的切面類??梢栽谥髋渲妙悾ㄍǔJ菃宇悾┲刑砑?nbsp;@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è)有一個服務(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)用之前、正常返回之后,以及拋出異常時,日志切面將分別記錄相關(guān)信息。

6. 總結(jié)

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

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

相關(guān)文章

  • Java的Atomic原子類詳解

    Java的Atomic原子類詳解

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

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

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

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

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

    Java中的延遲隊列DelayQueue源碼解析

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

    解決Springboot-application.properties中文亂碼問題

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

    詳解Spring IOC 容器啟動流程分析

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

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

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

    Java中Lambda表達式之Lambda語法與作用域解析

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

    全面解析Java中的HashMap類

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

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

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

最新評論