1. 程式人生 > 其它 >【Spring5】AOP

【Spring5】AOP

3 AOP

面向切面程式設計,利用AOP可以對業務的各個邏輯進行隔離,從而使得業務邏輯各部分的耦合度之間降低,提高程式的可重用性,同時提高開發的效率。

目的:不通過修改原始碼,在主幹功能上增加新功能

AOP底層原理

1.動態代理實現類方法增強

(1)有介面的情況:通過JDK方式建立介面實現類的代理物件

public class JDKProxy {
    public static void main(String[] args) {
        Class[] interfaces = {UserDao.class};

        UserDaoImpl userDao = new UserDaoImpl();
//        建立介面實現類的代理物件
//        代理的含義:不需要下面的介面實現類直接實現介面,而是通過代理的方式實現介面
//        UserDao userDao1 = new UserDaoImpl();

//        newProxyInstance返回介面實現類,第一個引數為當前類的類載入器,第二個引數是要實現介面的class陣列,第三個引數為增強邏輯後的介面實現類的代理類
        UserDao userDao1 = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));

        System.out.println(userDao1.add(1, 1));
    }
}

代理的含義:不需要下面的介面實現類直接實現介面,而是通過代理的方式實現介面
UserDao userDao1 = new UserDaoImpl();
UserDao userDao1 = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));

newProxyInstance返回介面實現類,第一個引數為當前類的類載入器,第二個引數是要實現介面的class陣列,第三個引數為增強邏輯後的介面實現類的代理類

編寫增強邏輯的介面實現類的代理類
obj表示代理物件的被代理方

class UserDaoProxy implements InvocationHandler {
    private Object obj;
    UserDaoProxy(Object obj) {
        this.obj = obj;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("方法執行前");
        Object res = method.invoke(obj, args);
        System.out.println(res);
        System.out.println("方法執行後");
        return res;
    }
}

(2)沒有介面的情況:通過CGLIB建立當前類的子類的代理物件

![](file://D:\資料\學習筆記\Java\Spring\1.png?msec=1649505122752)

AOP操作術語

1 連線點:類中可以被增強的方法

2 切入點:實際被真正增強的方法

3 通知(增強):實際增強的邏輯部分稱為通知(增強)

前置通知:

後置通知:

環繞通知:

異常通知:try-catch

最終通知:finally

4 切面

切面是一個動作:把通知應用到切入點的過程

AOP操作:基於AsepectJ實現AOP

AsepectJ不是Spring的組成部分,獨立於AOP框架,通常一起使用進行AOP操作。

兩種形式:基於xml配置檔案方式、基於註解方式

匯入jar包

spring-aspects-5.2.6.RELEASE.jar

com.springsource.net.sf.cglib-2.2.0.jar

com.springsource.org.aopalliance-1.0.0.jar

com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar

切入點表示式

作用:知道哪個類的哪個方法應該增強

語法結構:execution([許可權修飾符][返回型別][類全路徑][方法名稱] ( [引數列表] ) )

*表示所有

步驟

①建立類和增強類

②進行通知的配置,開啟註解元件掃描

xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
               http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
               http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.hikaru"></context:component-scan>

③新增建立類和增強類物件的註解,並在增強類上添加註解Aspect

@Component
public class User {
    public void add() {
        System.out.println("add...");
    }
}

@Component
@Aspect
public class UserProxy {

}

④在Spring配置檔案中開啟生成代理物件

<!--開啟Aspect生成代理物件-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

⑤配置不同型別的通知

@Component
@Aspect
public class UserProxy {
    @Before(value = "execution(* com.hikaru.User.add())")
    public void before() {
        System.out.println("before...");
    }

    @After(value = "execution(* com.hikaru.User.add(..))")
    public void after() {
        System.out.println("after...");
    }

    @AfterReturning(value = "execution(* com.hikaru.User.add(..))")
    public void afterReturn() {
        System.out.println("after return...");
    }

    @AfterThrowing(value = "execution(* com.hikaru.User.add(..))")
    public void afterThrowing() {
        System.out.println("afterThrowing...");
    }
    @Around(value = "execution(* com.hikaru.User.add(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("環繞之前");
        proceedingJoinPoint.proceed();
        System.out.println("環繞之後");
    }
}

環繞之前
before...
add...
環繞之後
after...
after return...

After與AfterReturning的區別:

After無論有沒有異常都會輸出,AfterReturning只有沒有異常正常返回時才會輸出。

異常時的結果:

環繞之前
before...
after...
afterThrowing...

公共切入點抽取:重用切入點定義

在增強類中:

    @Pointcut(value = "execution(* com.hikaru.User.add())")
    public void PointDemo() {

    }

通知中使用公共切入點

    @Before(value = "PointDemo()")
    public void before() {
        System.out.println("before...");
    }
有多個增強類對同一個類的同一個方法進行增強,應設定類優先順序

在增強類上添加註解@Order(數字特徵值),值越小表示優先順序越高

使用xml實現AOP操作

使用配置類代替配置檔案開啟Aspect生成代理物件,實現完全註解開發
@Configuration
@ComponentScan(value = {"com.hikaru"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class SpringConfig {

}
    @Test
    public void test() {
        ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        User user = context.getBean("user", User.class);
        user.add();
    }