SpringBoot AOP

一、引言

在軟件業(yè),AOP為Aspect Oriented Programming的縮寫,意為:面向切面編程,通過(guò)預(yù)編譯方式和運(yùn)行期動(dòng)態(tài)代理實(shí)現(xiàn)程序功能的統(tǒng)一維護(hù)的一種技術(shù)。
AOP是OOP的延續(xù),是軟件開發(fā)中的一個(gè)熱點(diǎn),也是Spring框架中的一個(gè)重要內(nèi)容,是函數(shù)式編程的一種衍生范型。
利用AOP可以對(duì)業(yè)務(wù)邏輯的各個(gè)部分進(jìn)行隔離,從而使得業(yè)務(wù)邏輯各部分之間的耦合度降低,提高程序的可重用性,同時(shí)提高了開發(fā)的效率。

主要功能

將日志記錄,性能統(tǒng)計(jì),安全控制,事務(wù)處理,異常處理等代碼從業(yè)務(wù)邏輯代碼中劃分出來(lái),通過(guò)對(duì)這些行為的分離,我們希望可以將它們獨(dú)立到非指導(dǎo)業(yè)務(wù)邏輯的方法中,進(jìn)而改變這些行為的時(shí)候不影響業(yè)務(wù)邏輯的代碼。

相關(guān)術(shù)語(yǔ)

目標(biāo)對(duì)象target:要增強(qiáng)的類
連接點(diǎn)(join point):增強(qiáng)類中所有的方法
切入點(diǎn)(pointcut):要具體增強(qiáng)的方法
通知(advice):具體要增強(qiáng)的功能代碼
切面aspect=切入點(diǎn)+通知
織入weaving
代理Proxy

AOP底層實(shí)現(xiàn)

Jdk動(dòng)態(tài)代理:基于接口,代理對(duì)象與目標(biāo)可理解為兄弟關(guān)系
CGLIB動(dòng)態(tài)代理:目標(biāo)對(duì)象與代理對(duì)象可理解為父子關(guān)系

二、知識(shí)點(diǎn)概要

SpringBoot AOP開發(fā)流程

1、添加 spring-boot-starter-aop,加入依賴,默認(rèn)就開始了AOP 的支持
2、寫一個(gè) Aspect,封裝橫切關(guān)注點(diǎn)(日志、監(jiān)控等),需要配置通知和切入點(diǎn)
3、這個(gè)Aspect 需要納入到spring容器管理,并且需要加入@Aspect

spring.aop.auto 配置項(xiàng)決定是否啟用AOP,默認(rèn)啟用

默認(rèn)是使用基于JDK的動(dòng)態(tài)代理來(lái)實(shí)現(xiàn)AOP
spring.aop.proxy-target-class=false 或者不配置,表示使用JDK的動(dòng)態(tài)代理
=true 表示使用了 cglib
如果配置了false,而類沒(méi)有接口,則依然使用cglib

三、AOP小Demo實(shí)現(xiàn)

1、目錄結(jié)構(gòu)如下
項(xiàng)目結(jié)構(gòu)
2、添加依賴
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
 </dependency>
3、創(chuàng)建UserDao 編寫個(gè)簡(jiǎn)單的測(cè)試方法
/**
 * @author liyao
 * @createTime 2018/8/14
 * @description
 */
@Component
public class UserDao {
    public void add(String username,String password){
        System.out.println("username"+username+",password:"+password);
    }
}
4、編寫切面LogAspect
/**
 * @author liyao
 * @createTime 2018/8/14
 * @description
 */

@Aspect
@Component
public class LogAspect {
    @Before("execution(* com.ly.aop.dao..*.*(..))")
    public void log(){
        System.out.println("method log done");
    }
}
5、測(cè)試結(jié)果
控制臺(tái)打印

四、AOP配置設(shè)置

1、是否啟用動(dòng)態(tài)代理,通過(guò)application.properties 配置

通過(guò)查看:
AopAutoConfiguration
api

得知配置:

#spring.aop.auto 配置項(xiàng)決定是否啟用AOP,默認(rèn)啟用
spring.aop.auto = true
#默認(rèn)是使用基于JDK的動(dòng)態(tài)代理來(lái)實(shí)現(xiàn)AOP
#spring.aop.proxy-target-class=false 或者不配置,表示使用JDK的動(dòng)態(tài)代理
#=true 表示使用了 cglib
#如果配置了false,而類沒(méi)有接口,則依然使用cglib
spring.aop.proxy-target-class = true
(1) Cglib 動(dòng)態(tài)代理配置
spring.aop.auto = true
#如果配置了false,而類沒(méi)有接口,則依然使用cglib
spring.aop.proxy-target-class = true

結(jié)果如圖:


cglib動(dòng)態(tài)代理
(2) JDK動(dòng)態(tài)代理配置

spring.aop.auto = false 則不會(huì)啟用
如下圖

未啟用

默認(rèn)是使用基于JDK的動(dòng)態(tài)代理來(lái)實(shí)現(xiàn)AOP,如果配置了false,而類沒(méi)有接口,則依然使用cglib,因?yàn)閖dk 動(dòng)態(tài)代理是基于接口實(shí)現(xiàn)的

spring.aop.auto = true
#如果配置了false,而類沒(méi)有接口,則依然使用cglib
spring.aop.proxy-target-class = false

結(jié)果如下圖:
仍然是 cglib 動(dòng)態(tài)代理方式

如何處理?
這里添加一個(gè)接口即可:

public interface IUserDao {
    public void add(String username,String password);
}
@Component
public class UserDao implements IUserDao {
        public void add(String username,String password){
            System.out.println("username:"+username+",password:"+password);
        }
}

結(jié)果如圖:
jdk動(dòng)態(tài)代理

2、獲取操作對(duì)象信息的一些api

/**
 * @author liyao
 * @createTime 2018/8/14
 * @description
 */

@Aspect
@Component
public class LogAspect {
    @Before("execution(* com.ly.aop.dao..*.*(..))")
    public void log(){
        System.out.println("before method log done");
        //System.out.println("before method log done" + AopContext.currentProxy().getClass());
    }
   /**
     * 獲取通知的信息
     * @param point
     */
    @After("execution(* com.ly.aop.dao..*.*(..))")
    public void logAfter(JoinPoint point){
        System.out.println("after method log done");
        System.out.println(
                 " 操作的對(duì)象:"+point.getTarget().getClass()+"args"
                + " 方法參數(shù):"+Arrays.asList(point.getArgs())
                + " 方法名:"+point.getSignature().getName());
    }
}

結(jié)果如圖:
aop

3、注解配置

@EnableAspectJAutoProxy 注解有兩個(gè)屬性
屬性

exproxy true ---> 可以 AopContext.currentProxy().getClass()獲取代理對(duì)象
exproxy false ---> 不可以獲取代理對(duì)象

@EnableAspectJAutoProxy(exposeProxy = true)
@SpringBootApplication
public class AopApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(AopApplication.class, args);
        System.out.println(context.getBean(IUserDao.class).getClass());
        context.getBean(IUserDao.class).add("admin","123");
        context.close();

    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容