(九)Spring-AOP 注解配置詳解

一、配置過程

  • ?配置依賴項,注意的是切入點表達(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

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

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