一、配置過程
- ?配置依賴項,注意的是切入點表達(dá)式解析的依賴包。
- ?配置切面類:
??@Aspect注解,表示當(dāng)前類是一個切面類
??@Pointcut替代xml文件中的切入點表達(dá)式,并且寫入切入點表達(dá)式
??@Before @AfterThrowing @AfterReturning @After @Around分別替代xml文件中的前置、異常、后置、最終以及環(huán)繞通知,需要注意的是,環(huán)繞通知與前面幾個通知選擇其一即可,環(huán)繞通知需要寫一個方法為public Object aopAround(ProceedingJoinPoint joinPoint),參數(shù)必須為要求的參數(shù),然后通過joinPoint來替代動態(tài)代理中的invoke。
??其余注解的配置與之前的配置一致,需要的注意的是在MyConfiguration類前需要加注解@EnableAspectJAutoProxy來開啟AOP代理。
二、配置步驟
?2.1 依賴項
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<groupId>org.example</groupId>
<artifactId>spring-account-annoation</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.2.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.48</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.7</version>
</dependency>
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
</dependencies>
</project>
?2.2 配置切面類及通知方法
package com.util;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.sql.SQLException;
/**
* Created with IntelliJ IDEA.
*
* @author : gxm
* @date : 2020/5/5
* @time : 21:25
* @projectName : spring-account
* @description : 工具類,控制連接的事務(wù),注解中配置為切面類
* 四個通知的注解使用會有順序調(diào)用問題,開發(fā)時應(yīng)選擇環(huán)繞通知,手動控制通知
* To change this template use File | Settings | File Templates.
* Description:
**/
@Component("transactionManager")
@Aspect
public class TransactionManager {
@Resource(name = "connectionUtils")
private ConnectionUtils connectionUtils;
public void setConnectionUtils(ConnectionUtils connectionUtils) {
this.connectionUtils = connectionUtils;
}
/**
* @author gxm
* @date 2020/5/8 15:38
* @description 配置切入點表達(dá)式
* @param
* @return void
* @since version-1.0
*/
@Pointcut("execution(* *.*.*.AccountServiceImpl.*(..))")
private void pointCut(){}
/**
* @param
* @return void
* @author gxm
* @date 2020/5/5 21:30
* @description 關(guān)閉當(dāng)前當(dāng)前線程連接的自動提交
* @since version-1.0
*/
@Before("pointCut()")
public void beginTransaction() {
System.out.println("beginTransaction");
try {
connectionUtils.getThreadConnection().setAutoCommit(false);
} catch (SQLException throwables) {
throw new RuntimeException(throwables);
}
}
/**
* @param
* @return void
* @author gxm
* @date 2020/5/5 21:30
* @description 出錯就回滾
* @since version-1.0
*/
@AfterThrowing("pointCut()")
public void rollBack() {
try {
connectionUtils.getThreadConnection().rollback();
} catch (SQLException throwables) {
throw new RuntimeException(throwables);
}
System.out.println("rollBack");
}
/**
* @param
* @return void
* @author gxm
* @date 2020/5/5 21:32
* @description 提交操作
* @since version-1.0
*/
@AfterReturning("pointCut()")
public void commit() {
System.out.println("commit");
try {
connectionUtils.getThreadConnection().commit();
} catch (SQLException throwables) {
throw new RuntimeException(throwables);
}
}
/**
* @param
* @return void
* @author gxm
* @date 2020/5/5 21:33
* @description This is description of method
* @since version-1.0
*/
@After("pointCut()")
public void release() {
System.out.println("release");
try {
connectionUtils.getThreadConnection().close();
connectionUtils.remove();
} catch (SQLException throwables) {
throw new RuntimeException(throwables);
}
}
/**
* @author gxm
* @date 22:44
* @description 環(huán)繞通知,類似于動態(tài)代理,手動實現(xiàn)aop過程
* @param joinPoint 1
* @return java.lang.Object
* @since version-1.0
*/
//@Around("pointCut()")
public Object aopAround(ProceedingJoinPoint joinPoint) {
Object proceed = null;
try {
// 1. 前置通知
beginTransaction();
// 2. 環(huán)繞通知
proceed = joinPoint.proceed(joinPoint.getArgs());
// 3. 后置通知
commit();
} catch (Throwable throwable) {
// 4. 異常通知
rollBack();
throw new RuntimeException(throwable);
}finally {
// 5. 最終通知
release();
}
return proceed;
}
}
?2.3 開啟AOP代理
@Configuration
@ComponentScan(value = "com")
@PropertySource("classpath:db.properties")
@Import(JdbcConfig.class)
@EnableAspectJAutoProxy
public class MyConfiguration {
}
?2.4 測試AOP代理是否正常執(zhí)行
package com.service.impl;
import com.config.MyConfiguration;
import com.domain.Account;
import com.service.IAccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
import java.util.List;
import static org.junit.Assert.*;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = MyConfiguration.class)
public class AccountServiceImplTest {
@Autowired
private IAccountService accountService;
@Qualifier("account")
@Autowired
private Account account1;
@Qualifier("account")
@Autowired
private Account account2;
// 更新數(shù)據(jù)庫時,添加如下測試代碼,報錯后,并未提交到數(shù)據(jù)庫,說明測試成功
//accounts1.forEach(this::updateAccount);
// int a = 1/0;
// accounts2.forEach(this::updateAccount);
@Test
public void transfer() {
account1.setId(17);
account2.setId(18);
accountService.transfer(account2, account1, 10f);
}
@Test
public void saveAccount() {
accountService.saveAccount(account1);
accountService.saveAccount(account2);
}
@Test
public void queryAll() {
List<Account> accounts = accountService.queryAll();
accounts.forEach((System.out::println));
}
@Test
public void queryById() {
List<Account> accounts = accountService.queryById(account1.getId());
accounts.forEach(System.out::println);
}
@Test
public void queryByName() {
List<Account> accounts = accountService.queryByName(account1.getName());
accounts.forEach(System.out::println);
}
@Test
public void updateAccount() {
account1.setBalance(account1.getBalance()+1);
accountService.updateAccount(account1);
}
@Test
public void deleteAccountById() {
accountService.deleteAccountById(account1.getId());
}
@Test
public void setAccountDao() {
}
}
?2.5 github完整代碼
https://github.com/GaoXiaoMing-BUPT/spring-account-annoation