十、SpringAOP基于注解的几种通知类型

首先要说明一点,spring基于注解的四种通知会有bug,所以实际开发,建议使用基于注解的环绕通知
首先pom依赖如下

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.6.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.5</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.2.6.RELEASE</version>
        </dependency>
    </dependencies>

AccountService接口

package com.lp.service;

/**
 * @Date 2020/5/29 14:37
 * @Author luopeng
 */
public interface AccountService {
    /**
     * 模拟保存账户
     */
    void saveAccount();

    /**
     * 模拟更新账户
     */
    void updateAccount();

    /**
     * 模拟删除账户
     */
    void deleteAccount(int id);
}

实现类

package com.lp.service.impl;

import com.lp.service.AccountService;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Service;

/**
 * @Date 2020/5/29 14:40
 * @Author luopeng
 */
@Service("accountService")
public class AccountServiceImpl implements AccountService {
    public void saveAccount() {
        System.out.println("执行了保存!");
        int i = 1/0;
    }

    public void updateAccount() {
        System.out.println("执行了更新!");

    }

    public void deleteAccount(int id) {
        System.out.println("执行了删除!"+id);

    }
}

写我们增强代码的工具类

package com.lp.utils;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * 用于记录日志的工具类,它里面提供了公共方法
 *
 * @Date 2020/5/29 14:41
 * @Author luopeng
 */
@Component
@Aspect
public class Logger {

    @Pointcut("execution(* com.lp.service.impl.*.*(..))")
    private void pt1(){}

    /**
     * 前置通知
     */
//    @Before("pt1()")
    public void beforePrintLog() {
        System.out.println("前置通知Logger类里面的printLog开始日志输入。。。");
    }

    /**
     * 后置通知
     */
//    @AfterReturning("pt1()")
    public void afterReturningPrintLog() {
        System.out.println("后置通知Logger类里面的printLog开始日志输入。。。");
    }

    /**
     * 异常通知
     */
//    @AfterThrowing("pt1()")
    public void afterThrowingPrintLog() {
        System.out.println("异常通知Logger类里面的printLog开始日志输入。。。");
    }

    /**
     * 最终通知
     */
//    @After("pt1()")
    public void afterPrintLog() {
        System.out.println("最终通知Logger类里面的printLog开始日志输入。。。");
    }

    /**
     * spring为我们提供了一个接口ProceedingJoinPoint
     * 该接口有一个proceed方法,此方法相当于明确调用切入点方法,
     * 我们可以将spring提供的接口作为方法参数,我们可调用该接口的实现类方法
     *spring中的环绕通知:
     *              我们可以手动控制增强方法何时执行
     * @param proceedingJoinPoint
     * @return
     * @throws Throwable
     */
    @Around("pt1()")
    public Object arruondPrintLog(ProceedingJoinPoint proceedingJoinPoint) {
        Object rtValue = null;
        //获取方法所需参数
        Object[] args = proceedingJoinPoint.getArgs();
        System.out.println("Logger类里面的printLog开始日志输入。。。前置");
        try {
            rtValue = proceedingJoinPoint.proceed(args);
            System.out.println("Logger类里面的printLog开始日志输入。。。后置");

        } catch (Throwable throwable) {
            throwable.printStackTrace();
            System.out.println("Logger类里面的printLog开始日志输入。。。异常");

        }finally {
            System.out.println("Logger类里面的printLog开始日志输入。。。最终");

        }


        return rtValue;
    }
}

此时我们需要spring的一个配置类

package com.lp.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

/**
 * @Date 2020/5/29 19:47
 * @Author luopeng
 */
@Configuration
@ComponentScan(basePackages = "com.lp")
@EnableAspectJAutoProxy
public class Config {
}

测试类如下

package com.lp.test;

import com.lp.config.Config;
import com.lp.service.AccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.annotation.Resource;

/**
 * @Date 2020/5/29 15:06
 * @Author luopeng
 */
@RunWith(value = SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = Config.class)
public class AOPTest {
    @Autowired
    private AccountService accountService;

    @Test
    public void test(){
        accountService.saveAccount();
    }

}

建议大家自己看完代码,理解记忆下来敲出来,虽然过程可能有点劳累,但你要相信,你没遇到一个错误就是你最大的收获,我刚刚找bug找了一个小时,就因为我RunWith里面的value值写错了,我去看了一下Runner的子类,就很大意的写成了BlockJUnit4ClassRunner,真想啪啪打自己的脸!不过以后都忘不了它给我带来的痛了!把它吞肚子里了,别想再一次欺负我!

猜你喜欢

转载自blog.csdn.net/lp20171401131/article/details/106431726