最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot中5種動(dòng)態(tài)代理的實(shí)現(xiàn)方案

 更新時(shí)間:2025年04月22日 08:10:16   作者:風(fēng)象南  
在SpringBoot應(yīng)用中,動(dòng)態(tài)代理被廣泛用于實(shí)現(xiàn)事務(wù)管理、緩存、安全控制、日志記錄等橫切關(guān)注點(diǎn),下面小編為大家介紹一下SpringBoot中5種動(dòng)態(tài)代理的實(shí)現(xiàn)方案吧

動(dòng)態(tài)代理允許我們?cè)诓恍薷脑创a的情況下,為對(duì)象增加額外的行為。在SpringBoot應(yīng)用中,動(dòng)態(tài)代理被廣泛用于實(shí)現(xiàn)事務(wù)管理、緩存、安全控制、日志記錄等橫切關(guān)注點(diǎn)。

1. JDK動(dòng)態(tài)代理:Java原生的代理方案

實(shí)現(xiàn)原理

JDK動(dòng)態(tài)代理是Java標(biāo)準(zhǔn)庫提供的代理機(jī)制,基于java.lang.reflect.Proxy類和InvocationHandler接口實(shí)現(xiàn)。它通過反射在運(yùn)行時(shí)動(dòng)態(tài)創(chuàng)建接口的代理實(shí)例。

核心代碼示例

public class JdkDynamicProxyDemo {
    interface UserService {
        void save(User user);
        User find(Long id);
    }
    
    // 實(shí)現(xiàn)類
    static class UserServiceImpl implements UserService {
        @Override
        public void save(User user) {
            System.out.println("保存用戶: " + user.getName());
        }
        
        @Override
        public User find(Long id) {
            System.out.println("查找用戶ID: " + id);
            return new User(id, "用戶" + id);
        }
    }
    
    // 調(diào)用處理器
    static class LoggingInvocationHandler implements InvocationHandler {
        private final Object target;
        
        public LoggingInvocationHandler(Object target) {
            this.target = target;
        }
        
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("Before: " + method.getName());
            long startTime = System.currentTimeMillis();
            
            Object result = method.invoke(target, args);
            
            long endTime = System.currentTimeMillis();
            System.out.println("After: " + method.getName() + ", 耗時(shí): " + (endTime - startTime) + "ms");
            
            return result;
        }
    }
    
    public static void main(String[] args) {
        // 創(chuàng)建目標(biāo)對(duì)象
        UserService userService = new UserServiceImpl();
        
        // 創(chuàng)建代理對(duì)象
        UserService proxy = (UserService) Proxy.newProxyInstance(
            userService.getClass().getClassLoader(),
            userService.getClass().getInterfaces(),
            new LoggingInvocationHandler(userService)
        );
        
        // 調(diào)用代理方法
        proxy.save(new User(1L, "張三"));
        User user = proxy.find(2L);
    }
}

優(yōu)點(diǎn)

  • JDK標(biāo)準(zhǔn)庫自帶:無需引入額外依賴,減少了項(xiàng)目體積
  • 生成代碼簡(jiǎn)單:代理邏輯集中在InvocationHandler中,易于理解和維護(hù)
  • 性能相對(duì)穩(wěn)定:在JDK 8后的版本中,性能有明顯提升

局限性

  • 只能代理接口:被代理類必須實(shí)現(xiàn)接口,無法代理類
  • 反射調(diào)用開銷:每次方法調(diào)用都需通過反射機(jī)制,有一定性能損耗
  • 無法攔截final方法:無法代理被final修飾的方法

Spring中的應(yīng)用

在Spring中,當(dāng)Bean實(shí)現(xiàn)了接口時(shí),默認(rèn)使用JDK動(dòng)態(tài)代理。這可以通過配置修改:

@EnableAspectJAutoProxy(proxyTargetClass = false) // 默認(rèn)值為false,表示優(yōu)先使用JDK動(dòng)態(tài)代理

2. CGLIB代理:基于字節(jié)碼的強(qiáng)大代理

實(shí)現(xiàn)原理

CGLIB(Code Generation Library)是一個(gè)強(qiáng)大的高性能字節(jié)碼生成庫,它通過繼承被代理類生成子類的方式實(shí)現(xiàn)代理。Spring從3.2版本開始將CGLIB直接集成到框架中。

核心代碼示例

public class CglibProxyDemo {
    // 不需要實(shí)現(xiàn)接口的類
    static class UserService {
        public void save(User user) {
            System.out.println("保存用戶: " + user.getName());
        }
        
        public User find(Long id) {
            System.out.println("查找用戶ID: " + id);
            return new User(id, "用戶" + id);
        }
    }
    
    // CGLIB方法攔截器
    static class LoggingMethodInterceptor implements MethodInterceptor {
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            System.out.println("Before: " + method.getName());
            long startTime = System.currentTimeMillis();
            
            // 調(diào)用原始方法
            Object result = proxy.invokeSuper(obj, args);
            
            long endTime = System.currentTimeMillis();
            System.out.println("After: " + method.getName() + ", 耗時(shí): " + (endTime - startTime) + "ms");
            
            return result;
        }
    }
    
    public static void main(String[] args) {
        // 創(chuàng)建CGLIB代理
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(UserService.class);
        enhancer.setCallback(new LoggingMethodInterceptor());
        
        // 創(chuàng)建代理對(duì)象
        UserService proxy = (UserService) enhancer.create();
        
        // 調(diào)用代理方法
        proxy.save(new User(1L, "張三"));
        User user = proxy.find(2L);
    }
}

優(yōu)點(diǎn)

  • 可以代理類:不要求目標(biāo)類實(shí)現(xiàn)接口,應(yīng)用場(chǎng)景更廣泛
  • 性能較高:通過生成字節(jié)碼而非反射調(diào)用,方法調(diào)用性能優(yōu)于JDK代理
  • 功能豐富:支持多種回調(diào)類型,如LazyLoader、Dispatcher等
  • 集成到Spring:Spring框架已內(nèi)置CGLIB,無需額外依賴

局限性

  • 無法代理final類和方法:由于使用繼承機(jī)制,無法代理final修飾的類或方法
  • 構(gòu)造函數(shù)調(diào)用:在生成代理對(duì)象時(shí)會(huì)調(diào)用目標(biāo)類的構(gòu)造函數(shù),可能導(dǎo)致意外行為
  • 復(fù)雜性增加:生成的字節(jié)碼復(fù)雜度高,調(diào)試?yán)щy
  • 對(duì)Java版本敏感:在不同Java版本間可能存在兼容性問題

Spring中的應(yīng)用

在Spring中,當(dāng)Bean沒有實(shí)現(xiàn)接口或配置了proxyTargetClass=true時(shí),使用CGLIB代理:

@EnableAspectJAutoProxy(proxyTargetClass = true) // 強(qiáng)制使用CGLIB代理

3. ByteBuddy:現(xiàn)代化的字節(jié)碼操作庫

實(shí)現(xiàn)原理

ByteBuddy是一個(gè)相對(duì)較新的字節(jié)碼生成和操作庫,設(shè)計(jì)更加現(xiàn)代化,API更加友好。它可以創(chuàng)建和修改Java類,而無需理解底層的JVM指令集。

核心代碼示例

public class ByteBuddyProxyDemo {
    interface UserService {
        void save(User user);
        User find(Long id);
    }
    
    static class UserServiceImpl implements UserService {
        @Override
        public void save(User user) {
            System.out.println("保存用戶: " + user.getName());
        }
        
        @Override
        public User find(Long id) {
            System.out.println("查找用戶ID: " + id);
            return new User(id, "用戶" + id);
        }
    }
    
    static class LoggingInterceptor {
        @RuntimeType
        public static Object intercept(@Origin Method method, @SuperCall Callable<?> callable,
                                       @AllArguments Object[] args) throws Exception {
            System.out.println("Before: " + method.getName());
            long startTime = System.currentTimeMillis();
            
            Object result = callable.call();
            
            long endTime = System.currentTimeMillis();
            System.out.println("After: " + method.getName() + ", 耗時(shí): " + (endTime - startTime) + "ms");
            
            return result;
        }
    }
    
    public static void main(String[] args) throws Exception {
        UserService userService = new UserServiceImpl();
        
        // 創(chuàng)建ByteBuddy代理
        UserService proxy = new ByteBuddy()
            .subclass(UserServiceImpl.class)
            .method(ElementMatchers.any())
            .intercept(MethodDelegation.to(new LoggingInterceptor()))
            .make()
            .load(UserServiceImpl.class.getClassLoader())
            .getLoaded()
            .getDeclaredConstructor()
            .newInstance();
        
        // 調(diào)用代理方法
        proxy.save(new User(1L, "張三"));
        User user = proxy.find(2L);
    }
}

優(yōu)點(diǎn)

  • 流暢的API:提供鏈?zhǔn)骄幊田L(fēng)格,代碼更加可讀
  • 性能卓越:在多項(xiàng)基準(zhǔn)測(cè)試中,性能優(yōu)于CGLIB和JDK代理
  • 類型安全:API設(shè)計(jì)更注重類型安全,減少運(yùn)行時(shí)錯(cuò)誤
  • 支持Java新特性:對(duì)Java 9+模塊系統(tǒng)等新特性有更好的支持
  • 功能豐富:支持方法重定向、字段訪問、構(gòu)造函數(shù)攔截等多種場(chǎng)景

局限性

  • 額外依賴:需要引入額外的依賴庫
  • 學(xué)習(xí)曲線:API雖然流暢,但概念較多,有一定學(xué)習(xí)成本
  • 在Spring中集成度不高:需要自定義配置才能在Spring中替代默認(rèn)代理機(jī)制

Spring中的應(yīng)用

ByteBuddy雖然不是Spring默認(rèn)的代理實(shí)現(xiàn),但可以通過自定義ProxyFactory來集成:

@Configuration
public class ByteBuddyProxyConfig {
    @Bean
    public AopConfigurer byteBuddyAopConfigurer() {
        return new AopConfigurer() {
            @Override
            public void configureProxyCreator(Object bean, String beanName) {
                // 配置ByteBuddy作為代理創(chuàng)建器
                // 實(shí)現(xiàn)細(xì)節(jié)略
            }
        };
    }
}

4. Javassist:更易用的字節(jié)碼編輯庫

實(shí)現(xiàn)原理

Javassist是一個(gè)開源的Java字節(jié)碼操作庫,提供了兩個(gè)層次的API:源代碼級(jí)別和字節(jié)碼級(jí)別。它允許開發(fā)者用簡(jiǎn)單的Java語法直接編輯字節(jié)碼,無需深入了解JVM規(guī)范。

核心代碼示例

public class JavassistProxyDemo {
    interface UserService {
        void save(User user);
        User find(Long id);
    }
    
    static class UserServiceImpl implements UserService {
        @Override
        public void save(User user) {
            System.out.println("保存用戶: " + user.getName());
        }
        
        @Override
        public User find(Long id) {
            System.out.println("查找用戶ID: " + id);
            return new User(id, "用戶" + id);
        }
    }
    
    public static void main(String[] args) throws Exception {
        ProxyFactory factory = new ProxyFactory();
        
        // 設(shè)置代理接口
        factory.setInterfaces(new Class[] { UserService.class });
        
        // 創(chuàng)建方法過濾器
        MethodHandler handler = new MethodHandler() {
            private UserService target = new UserServiceImpl();
            
            @Override
            public Object invoke(Object self, Method method, Method proceed, Object[] args) throws Throwable {
                System.out.println("Before: " + method.getName());
                long startTime = System.currentTimeMillis();
                
                Object result = method.invoke(target, args);
                
                long endTime = System.currentTimeMillis();
                System.out.println("After: " + method.getName() + ", 耗時(shí): " + (endTime - startTime) + "ms");
                
                return result;
            }
        };
        
        // 創(chuàng)建代理對(duì)象
        UserService proxy = (UserService) factory.create(new Class<?>[0], new Object[0], handler);
        
        // 調(diào)用代理方法
        proxy.save(new User(1L, "張三"));
        User user = proxy.find(2L);
    }
}

優(yōu)點(diǎn)

  • 源代碼級(jí)API:可以不懂字節(jié)碼指令集,以Java代碼形式操作字節(jié)碼
  • 輕量級(jí)庫:相比其他字節(jié)碼庫體積較小
  • 功能全面:支持創(chuàng)建類、修改類、動(dòng)態(tài)編譯Java源代碼等
  • 性能良好:生成的代理代碼性能接近CGLIB
  • 長期維護(hù):庫歷史悠久,穩(wěn)定可靠

局限性

  • API不夠直觀:部分API設(shè)計(jì)較為古老,使用不如ByteBuddy流暢
  • 文檔不足:相比其他庫,文檔和示例較少
  • 內(nèi)存消耗:在操作大量類時(shí)可能消耗較多內(nèi)存

Spring中的應(yīng)用

Javassist不是Spring默認(rèn)的代理實(shí)現(xiàn),但一些基于Spring的框架使用它實(shí)現(xiàn)動(dòng)態(tài)代理,如Hibernate:

// 自定義Javassist代理工廠示例
public class JavassistProxyFactory implements ProxyFactory {
    @Override
    public Object createProxy(Object target, Interceptor interceptor) {
        // Javassist代理實(shí)現(xiàn)
        // ...
    }
}

5. AspectJ:完整的AOP解決方案

實(shí)現(xiàn)原理

AspectJ是一個(gè)完整的AOP框架,與前面的動(dòng)態(tài)代理方案不同,它提供兩種方式:

  • 編譯時(shí)織入:在編譯源代碼時(shí)直接修改字節(jié)碼
  • 加載時(shí)織入:在類加載到JVM時(shí)修改字節(jié)碼

AspectJ擁有專門的切面語言,功能比Spring AOP更強(qiáng)大。

核心代碼示例

AspectJ切面定義:

@Aspect
public class LoggingAspect {
    @Before("execution(* com.example.service.UserService.*(..))")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("Before: " + joinPoint.getSignature().getName());
    }
    
    @Around("execution(* com.example.service.UserService.*(..))")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("Before: " + joinPoint.getSignature().getName());
        long startTime = System.currentTimeMillis();
        
        Object result = joinPoint.proceed();
        
        long endTime = System.currentTimeMillis();
        System.out.println("After: " + joinPoint.getSignature().getName() + 
                          ", 耗時(shí): " + (endTime - startTime) + "ms");
        
        return result;
    }
}

Spring配置AspectJ:

@Configuration
@EnableAspectJAutoProxy
public class AspectJConfig {
    @Bean
    public LoggingAspect loggingAspect() {
        return new LoggingAspect();
    }
}

編譯時(shí)織入配置(maven):

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>aspectj-maven-plugin</artifactId>
    <version>1.14.0</version>
    <configuration>
        <complianceLevel>11</complianceLevel>
        <source>11</source>
        <target>11</target>
        <aspectLibraries>
            <aspectLibrary>
                <groupId>org.springframework</groupId>
                <artifactId>spring-aspects</artifactId>
            </aspectLibrary>
        </aspectLibraries>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>compile</goal>
            </goals>
        </execution>
    </executions>
</plugin>

優(yōu)點(diǎn)

  • 功能最全面:支持幾乎所有AOP場(chǎng)景,包括構(gòu)造函數(shù)、字段訪問、異常等
  • 性能最優(yōu):編譯時(shí)織入無運(yùn)行時(shí)開銷,性能接近原生代碼
  • 完整語言支持:有專門的切面語言和語法,表達(dá)能力強(qiáng)
  • 更靈活的切入點(diǎn):可以對(duì)接口、實(shí)現(xiàn)類、構(gòu)造函數(shù)、字段等定義切面

局限性

  • 復(fù)雜度高:學(xué)習(xí)曲線陡峭,需要掌握AspectJ語法
  • 構(gòu)建過程改變:需要特殊的編譯器或類加載器
  • 調(diào)試難度增加:修改后的字節(jié)碼可能難以調(diào)試

Spring中的應(yīng)用

Spring可以通過以下方式使用AspectJ:

proxy-target-class模式:使用Spring AOP但CGLIB生成的代理

@EnableAspectJAutoProxy(proxyTargetClass = true)

LTW(Load-Time Weaving)模式:在類加載時(shí)織入

@EnableLoadTimeWeaving

編譯時(shí)織入:需要配置AspectJ編譯器

使用場(chǎng)景對(duì)比與選擇建議

代理實(shí)現(xiàn)最適用場(chǎng)景不適用場(chǎng)景
JDK動(dòng)態(tài)代理基于接口的簡(jiǎn)單代理,輕量級(jí)應(yīng)用沒有實(shí)現(xiàn)接口的類,性能敏感場(chǎng)景
CGLIB沒有實(shí)現(xiàn)接口的類,需要兼顧性能和便捷性final類/方法,高安全性環(huán)境
ByteBuddy現(xiàn)代化項(xiàng)目,關(guān)注性能優(yōu)化,復(fù)雜代理邏輯追求最小依賴的簡(jiǎn)單項(xiàng)目
Javassist需要?jiǎng)討B(tài)生成/修改類的復(fù)雜場(chǎng)景API設(shè)計(jì)敏感項(xiàng)目,初學(xué)者
AspectJ企業(yè)級(jí)應(yīng)用,性能關(guān)鍵型場(chǎng)景,復(fù)雜AOP需求簡(jiǎn)單項(xiàng)目,快速原型,學(xué)習(xí)成本敏感

到此這篇關(guān)于SpringBoot中5種動(dòng)態(tài)代理的實(shí)現(xiàn)方案的文章就介紹到這了,更多相關(guān)SpringBoot動(dòng)態(tài)代理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Tk.mybatis零sql語句實(shí)現(xiàn)動(dòng)態(tài)sql查詢的方法(4種)

    Tk.mybatis零sql語句實(shí)現(xiàn)動(dòng)態(tài)sql查詢的方法(4種)

    有時(shí)候,查詢數(shù)據(jù)需要根據(jù)條件使用動(dòng)態(tài)查詢,這時(shí)候需要使用動(dòng)態(tài)sql,本文主要介紹了Tk.mybatis零sql語句實(shí)現(xiàn)動(dòng)態(tài)sql查詢的方法,感興趣的可以了解一下
    2021-12-12
  • Java groovy如何提升代碼運(yùn)行效率

    Java groovy如何提升代碼運(yùn)行效率

    這篇文章主要介紹了Java groovy如何提升代碼運(yùn)行效率,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-09-09
  • Java線程并發(fā)訪問代碼分析

    Java線程并發(fā)訪問代碼分析

    這篇文章主要介紹了Java線程并發(fā)訪問代碼分析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11
  • 在Java的Struts框架下進(jìn)行web編程的入門教程

    在Java的Struts框架下進(jìn)行web編程的入門教程

    這篇文章主要介紹了在Java的Struts框架下進(jìn)行web編程的入門教程,需要的朋友可以參考下
    2015-11-11
  • SpringBoot 中的 @Transactional 事務(wù)基本作用及注意事項(xiàng)示例詳解

    SpringBoot 中的 @Transactional 事務(wù)基本作用及注意事項(xiàng)示例詳解

    @Transactional是SpringBoot中聲明式事務(wù)管理的核心注解,通過注解簡(jiǎn)化事務(wù)控制,確保操作的原子性,支持異?;貪L、隔離級(jí)別和傳播行為配置,需注意代理模式、異常拋出及數(shù)據(jù)庫支持等條件,避免事務(wù)失效,本文介紹SpringBoot @Transactional事務(wù)作用,感興趣的朋友一起看看吧
    2025-09-09
  • springboot如何配置上傳文件的maxRequestSize

    springboot如何配置上傳文件的maxRequestSize

    這篇文章主要介紹了springboot如何配置上傳文件的maxRequestSize,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • Java中操作數(shù)組的Arrays類

    Java中操作數(shù)組的Arrays類

    大家好,本篇文章主要講的是Java中操作數(shù)組的Arrays類,感興趣的同學(xué)趕快來看一看吧,對(duì)你有幫助的話記得收藏一下
    2022-02-02
  • Java中的equsals和==

    Java中的equsals和==

    這篇文章主要介紹了Java中的equsals和==的相關(guān)內(nèi)容,感興趣的朋朋友可以參考下文
    2021-08-08
  • Spring Boot中使用@Scheduled和Quartz實(shí)現(xiàn)定時(shí)任務(wù)的詳細(xì)過程

    Spring Boot中使用@Scheduled和Quartz實(shí)現(xiàn)定時(shí)任務(wù)的詳細(xì)過程

    Spring Boot提供了兩種常見的定時(shí)任務(wù)實(shí)現(xiàn)方式,一種是基于@Scheduled注解的簡(jiǎn)單定時(shí)任務(wù),另一種是功能更強(qiáng)大的Quartz框架,本文將介紹如何在Spring Boot中使用這兩種方式實(shí)現(xiàn)定時(shí)任務(wù)和調(diào)度功能,感興趣的朋友一起看看吧
    2025-08-08
  • Java中FileOutputStream流的write方法

    Java中FileOutputStream流的write方法

    這篇文章主要為大家詳細(xì)介紹了Java中FileOutputStream流的write方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-08-08

最新評(píng)論

政和县| 西安市| 焦作市| 温州市| 即墨市| 柘荣县| 化德县| 娱乐| 大同市| 隆林| 怀来县| 高平市| 鄄城县| 怀宁县| 白河县| 皋兰县| 汉寿县| 运城市| 渝中区| 琼海市| 平远县| 康保县| 固始县| 武强县| 叙永县| 民乐县| 陇川县| 宁武县| 太仓市| 桃源县| 宁津县| 大兴区| 醴陵市| 眉山市| 修文县| 军事| 滨海县| 东至县| 儋州市| 泾川县| 铜川市|