Spring學習筆記(十一)AOP的註解方式cglib代理
阿新 • • 發佈:2019-02-11
JDK動態代理與CGLib動態代理均是實現Spring AOP的基礎,切點,切面,如何定義切點,前置、後置、放回、異常、環繞通知
1.切點、切面
- 紅色的地方就是切面,增加額外的功能
- 連線點+增加功能的位置 = 切點
2.專案結構
3.jar包
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version> 4.11</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version >4.3.6.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.6.RELEASE</version >
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.6.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.6.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context-support -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.6.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.6.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-expression -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>4.3.6.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-tx -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.3.6.RELEASE</version>
</dependency>
<!--新增的jar-->
<!-- https://mvnrepository.com/artifact/aopalliance/aopalliance -->
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.13</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.6</version>
</dependency>
</dependencies>
4.核心配置檔案beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd">
<!--1.啟動Spring註解-->
<context:annotation-config></context:annotation-config>
<!--2.掃描-->
<context:component-scan base-package="com.hs"/>
<!--Spring提供了多種AOP的實現方式,但是我們只用第三方的AOP標準方式-->
<!--3.啟動AOP註解,false是使用預設的java代理,true是使用CGLIB代理-->
<aop:aspectj-autoproxy proxy-target-class="true"/>
</beans>
5.核心程式碼
package com.hs.service;
/**
* 對外提供的核心業務,完成了加法/減法/乘法運算
*/
public interface ArithmeticService {
int add(int x, int y);
int sub(int x, int y);
int mul(int x, int y);
int div(int x, int y);
}
package com.hs.service.impl;
import com.hs.service.ArithmeticService;
import org.springframework.stereotype.Service;
/**
* 核心程式碼
*/
@Service
public class ArithmeticServiceImpl implements ArithmeticService {
@Override
public int add(int x, int y) {
//核心程式碼
int result = x + y;
return result;
}
@Override
public int sub(int x, int y) {
int result = x - y;
return result;
}
@Override
public int mul(int x, int y) {
int result = x * y;
return result;
}
@Override
public int div(int x, int y) {
int result = x / y;
return result;
}
}
6.定義切面
package com.hs.service.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.util.Arrays;
@Component
@Aspect //標記這是切面
public class Logger {
//在你執行方法之前執行,並且監控的是介面的執行Add方法,value可以省略
@Before(value = "execution(int com.hs.service.ArithmeticService.add(int ,int))")
//這句話的意思,
//執行返回型別為int,com.hs.service.ArithmeticService介面下的add方法,傳遞的兩個引數型別為int,int
//簡單理解為,接口裡寫的方法,只是少了變數值 int add(int x, int y);
public void test01() {
System.out.println("@Before在程式之前執行");
}
}
測試
package com.hs.test;
import com.hs.service.ArithmeticService;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ArithmeticServiceTest {
private ArithmeticService arithmeticService;
private ApplicationContext ac;
@Before
public void init() {
this.ac = new ClassPathXmlApplicationContext("beans.xml");
this.arithmeticService = this.ac.getBean("arithmeticServiceImpl", ArithmeticService.class);
}
@Test
public void testAddMethod() {
int result = this.arithmeticService.add(2,1);
System.out.println("執行的結果:"+ result);
}
}
控制檯輸出:
@Before在程式之前執行
執行的結果:3
7.如何定義註解切點說明
1.使用邏輯運算子
@Before(value = "execution(int com.hs.service.ArithmeticService.add(int ,int)) or execution(int com.hs.service.ArithmeticService.sub(int ,int))")
public void test02() {
System.out.println("我可以使用邏輯運算子 &&(and) ||(or)");
}
2.使用萬用字元——推薦
/**
* 比較推薦
* 在execution表示式中可以使用萬用字元,但是請注意任意的表示式是 ..
* 第一個*位置:代表返回任意的資料型別
* ..表示任意的意思,而不是我們之前學習的**
* 第二個* 監控的以Service結尾的類(介面)
* 第三個* 監控介面或者類下的所有的方法
* ..標識任意個引數型別或者引數的個數
*/
@Before(value = "execution(* com.hs..*Service.*(..))")
public void test03() {
System.out.println("我可以使用萬用字元");
}
3.如何定義切點
//如何定義切點(可以隨意組合)
@Pointcut(value = "execution(int com.hs.service.ArithmeticService.add(int ,int))")
public void addPointCut() { } //切點的名稱是“addPointCut()”
@Pointcut(value = "execution(int com.hs.service.ArithmeticService.sub(int ,int))")
public void subPointCut() { } //切點的名稱是“subPointCut()”
@Pointcut(value = "execution(int com.hs.service.ArithmeticService.mul(int ,int))")
public void mulPointCut() { } //切點的名稱是“mulPointCut()”
@Pointcut(value = "addPointCut() || mulPointCut()")
public void addAndMulPointCut() { } //切點的名稱是“addAndMulPointCut()”
@Pointcut(value = "execution(* com.hs..service.*Service.*(..))")
public void allMethodPointCut(){}
//@Before 叫前置通知,也叫前置增強
@Before(value = "addAndMulPointCut()")
public void test04() {
System.out.println("如何定義切點");
}
8.前置通知:不管程式是否正確都會執行
//1.前置通知(增強)特點:不管程式是否正確都會執行
@Before(value = "allMethodPointCut()")
public void test05(JoinPoint jp) {
System.out.println("==前置通知==");
//獲取get
System.out.println(Arrays.asList(jp.getArgs()));
System.out.println(jp.getSignature().getName());
System.out.println(jp.getTarget().getClass().getName());
System.out.println("==前置通知==");
}
9.後置通知:不管程式是否正確都會執行
//2.後置通知(增強)特點:不管程式是否正確都會執行
@After(value = "allMethodPointCut()")
public void test06(JoinPoint jp) {
//獲取get
System.out.println("==後置增強==");
System.out.println(Arrays.asList(jp.getArgs()));
System.out.println(jp.getSignature().getName());
System.out.println(jp.getTarget().getClass().getName());
System.out.println("==後置增強==");
}
10.返回通知:只有程式是正確的時候才會執行,並且可以獲取執行後的資料
//3.返回通知(增強):只有程式是正確的時候才會執行,並且可以獲取執行後的資料
@AfterReturning(value = "allMethodPointCut()",returning = "hs")
public void test07(JoinPoint jp,int hs) {
System.out.println("==返回通知==");
System.out.println("程式正常執行,正確的執行結果為==>"+hs);
System.out.println("==返回通知==");
}
11.異常通知:只有程式是錯誤的時候才會執行
//4.異常通知(增強):只有程式是錯誤的時候才會執行,
@AfterThrowing(value = "allMethodPointCut()",throwing = "hs")
public void test08(JoinPoint jp,ArithmeticException hs) {
System.out.println("==異常通知==");
System.out.println("程式執行錯誤==>"+hs);
System.out.println("==異常通知==");
}
12.環繞通知
//5.環繞通知
@Around("allMethodPointCut()")
public Object test09(ProceedingJoinPoint pjp) {
System.out.println("寫某個功能,前置通知");
Object result = null;
try {
result = pjp.proceed(); //執行程式返回執行的結果
System.out.println("寫某個功能,返回通知");
} catch (Throwable throwable) {
throwable.printStackTrace();
System.out.println("寫某個功能,異常通知");
}
System.out.println("寫某個功能,後置通知");
return result;
}
測試
package com.hs.test;
import com.hs.service.ArithmeticService;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ArithmeticServiceTest {
private ArithmeticService arithmeticService;
private ApplicationContext ac;
@Before
public void init() {
this.ac = new ClassPathXmlApplicationContext("beans.xml");
this.arithmeticService = this.ac.getBean("arithmeticServiceImpl", ArithmeticService.class);
}
@Test
public void testAddMethod() {
int result = this.arithmeticService.add(2,1);
System.out.println("執行的結果:"+ result);
}
}