【Spring Boot實戰與進階】AOP的兩種動態代理(JDK和Cglib)

Spring Boot是很優秀的框架,它的出現簡化了新Spring應用的初始搭建以及開發過程,大大減少了代碼量,目前已被大多數企業認可和使用。這個專欄將對Spring Boot框架從淺入深,從實戰到進階,不但我們要懂得如何去使用,還要去剖析框架源碼,學習其優秀的設計思想。

彙總目錄鏈接:【Spring Boot實戰與進階】學習目錄

一、JDK和Cglib兩種動態代理方式區別

  1、java動態代理是利用反射機制生成一個實現代理接口的匿名類,在調用具體方法前調用InvokeHandler來處理。而Cglib動態代理是利用asm開源包,對代理對象類的class文件加載進來,通過修改其字節碼生成子類來處理。
  2、JDK動態代理只能對實現了接口的類生成代理,而不能針對類;Cglib是針對類實現代理,主要是對指定的類生成一個子類,覆蓋其中的方法,因爲是繼承,所以該類或方法最好不要聲明成final 。
  3、Cglib一個目標類方法會生成兩個代理方法,一個重寫目標方法,並實現代理邏輯,還有一個直接調用目標類方法。

二、AOP的實現原理

想了解原理的可以看這篇【Spring教程】詳解AOP的實現原理(動態代理),接下來我們直接通過示例講如何使用。

1、 引入AOP依賴

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

2、AOP的配置

2.1 基於Spring的AOP寫法

spring.aop.auto=true # 是否啓用aop
spring.aop.proxy-target-class=false # 代理方式有接口使用jdk動態代理,如果沒有接口使用cglib代理;設置爲true時表示強制使用cglib代理

2.2 基於SpringBoot做法 @EnableAopProxyClass

exposeProxy屬性表示如果使用true就可以使用AopContext對象獲取當前代理對象,false則不能使用
proxyTargetClass true表示使用jdk的動態代理, false表示使用cglib代理

示例一(Cglib動態代理,默認)

1、BookDaoImpl

@Repository
public class BookDaoImpl implements BookDao {

    @Override
    public void addBook(String name, String author) {
        System.out.println("BookDaoImpl實現類:bookName:"+name+", bookAuthor:"+author);
    }
}

2、BookAop

@Component
@Aspect
public class BookAop {
    // 定義切入點
    public static final String POINT_CUT = "execution(* com.example.bootaop.dao..*.*(..))";

    @Before(POINT_CUT)
    public void before() {
        System.out.println("----------添加圖書方法前[校驗]-----------");
    }

    @After(POINT_CUT)
    public void after(JoinPoint jp) {
        System.out.println("----------添加圖書成功後-----------");
        System.out.println(jp.getTarget().getClass());
        System.out.println(Arrays.asList(jp.getArgs()));
    }
}

3、BootAopApplication

@SpringBootApplication
public class BootAopApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext
                context = SpringApplication.run(BootAopApplication.class, args);
        BookDaoImpl bookDao = context.getBean(BookDaoImpl.class);
        System.out.println(bookDao.getClass());
        bookDao.addBook("神鵰俠侶", "金庸");
        context.close();
    }
}

控制檯輸出

class com.example.bootaop.dao.BookDaoImpl$$EnhancerBySpringCGLIB$$2d857802
----------添加圖書方法前[校驗]-----------
BookDaoImpl實現類:bookName:神鵰俠侶, bookAuthor:金庸
----------添加圖書成功後-----------
class com.example.bootaop.dao.BookDaoImpl
[神鵰俠侶, 金庸]

示例二(JDK動態代理,只能對實現了接口的類生成代理)

1、BookDao

@Repository
public class BookDaoImpl1 implements BookDao {
    @Override
    public void addBook(String name, String author) {

    }
}

2、BookDaoImpl1

@Repository
public class BookDaoImpl1 implements BookDao {
    @Override
    public void addBook(String name, String author) {

    }
}

3、BootAopApplication

@SpringBootApplication
public class BootAopApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext
                context = SpringApplication.run(BootAopApplication.class, args);
        BookDao bookDao = context.getBean("bookDaoImpl1", BookDao.class);//多個實現類時
        System.out.println(bookDao.getClass());
        bookDao.addBook("鹿鼎記", "金庸");
        context.close();
    }
}

配置文件增加:spring.aop.proxy-target-class=false
控制檯輸出

class com.sun.proxy.$Proxy61
----------添加圖書方法前[校驗]-----------
----------添加圖書成功後-----------
class com.example.bootaop.dao.BookDaoImpl1
[鹿鼎記, 金庸]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章