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
[鹿鼎記, 金庸]