SpringBootAOP切面编程方法拦截和自定义注解拦截实现灵活的AOP切面配置

前言

切面很多时候都可以用到,多数据源动态切换,AOP编程检查权限是否开启,AOP编程检查网络状态是否可用,AOP检查用户登录,AOP用户行为统计,AOP日志等。当为一个系统添加新的功能的时候又不能修改原来的代码 ,这个时候就可以使用aop技术。当为多个类添加相同的功能的时候就可以使用aop技术,当为业务方法增加事务或者日志输出的时候可以使用aop技术。

AOP

所谓AOP是面向切面编程。即:在不改变原来代码的基础上,实现功能的扩展(增加)。

切面

切面:由切点、前置通知、后置通知这三部分织成的一个横向的平面。

① 切点
  前面已经说到,AOP就是:在不改变原来代码的基础上,实现功能的扩展(增加)。
  首先我们要清楚明白我们要对哪个功能方法进行扩展,比如说我们对a()方法进行功能扩展。我们把a()方法称为:切点。
  
② 前置通知
  在切点之前执行的扩展方法。
  
③ 后置通知
  在切点之后执行的扩展方法。

在这里插入图片描述

在这里插入图片描述

一张图简单的解释AOP思想

在这里插入图片描述

用法

数据库数据为以下:
在这里插入图片描述

1.添加依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

2、编写UserServiceImpl类

package com.dalaoyang.serviceImpl;

import ch.qos.logback.core.db.dialect.DBUtil;
import com.dalaoyang.config.DataSource;
import com.dalaoyang.dao.UserMapper;
import com.dalaoyang.entity.User;
import com.dalaoyang.utils.DbUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.List;

@Service
public class UserServiceImpl {

    @Autowired
    UserMapper userMapper;

    public String getUser(){
    User user =userMapper.findUserByUsername("dalaoyang");
        return user!=null ? "dalaoyang"+"的密码是:"+user.getUser_password():"不存在用户名为"+"dalaoyang"+"的用户";
    }

    public String setUser(){
        User user =userMapper.findUserByUsername("xiaoli");
        return user!=null ? "xiaoli"+"的密码是:"+user.getUser_password():"不存在用户名为"+"xiaoli"+"的用户";
    }


    public String ALLUser(){
        List<User> userList =userMapper.getUserList();
        return userList.toString() ;
    }

    @DataSource(DbUtil.DB_MASTER2)
    public String findUser(){
        User user =userMapper.findUserByUsername("xiaoxiongmao");
        return user!=null ? "xiaoxiongmao"+"的密码是:"+user.getUser_password():"不存在用户名为"+"xiaoxiongmao"+"的用户";
    }



}

3、编写普通方法AOP类

package com.dalaoyang.config;

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

import java.lang.reflect.Method;

@Aspect
@Component
public class AOPAspect {

    @Pointcut(value = "execution(* com.dalaoyang.serviceImpl.UserServiceImpl.get*(..))")  //注意这里是全文件匹配函数
    public void getPoint() {
    }

    @Pointcut(value = "execution(* com.dalaoyang.serviceImpl.UserServiceImpl.set*(..))")  //注意这里是全文件匹配函数
    public void setPoint() {
    }

    @Before("getPoint()")
    public void getPointAcc1(){
        System.out.println("BeforeGetPoint");
    }

    @After("getPoint()")
    public void getPointAcc2(){
        System.out.println("AfterGetPoint");
    }

    @Before("setPoint()")
    public void setPointAcc1(){
        System.out.println("BeforeSetPoint");
    }

    @After("setPoint()")
    public void setPointAcc2(){
        System.out.println("AfterSetPoint");
    }

    @Around("getPoint()")
    public Object getDoAround(ProceedingJoinPoint pjp){
        ThreadLocal<Long> startTime = new ThreadLocal<>();
        startTime.set(System.currentTimeMillis());
        System.out.println("我是环绕通知执行");
        Object obj;
        try{
            obj = pjp.proceed();  //启动目标方法执行
            System.out.println("执行返回值 : " + obj);
            Signature s = pjp.getSignature();
            System.out.println(pjp.getSignature().getName()+"方法执行耗时: " + 
            (System.currentTimeMillis() - startTime.get()));
        } catch (Throwable throwable) {
            obj=throwable.toString();
        }
        return obj;
    }

    @Around("setPoint()")
    public Object setDoAround(ProceedingJoinPoint pjp){
        ThreadLocal<Long> startTime = new ThreadLocal<>();
        startTime.set(System.currentTimeMillis());
        System.out.println("我是环绕通知执行");
        Object obj;
        try{
            obj = pjp.proceed();  //启动目标方法执行
            System.out.println("执行返回值 : " + obj);
            Signature s = pjp.getSignature();
            System.out.println(pjp.getSignature().getName()+"方法执行耗时: " +
             (System.currentTimeMillis() - startTime.get()));
        }catch (Throwable throwable) {
            obj=throwable.toString();
        }
        return obj;
    }

    /**
     * 执行完请求可以做的
     * @param result
     * @throws Throwable
     */
    @AfterReturning(returning = "result", pointcut = "getPoint()||setPoint()")
    public void doAfterReturning(Object result){
        System.out.println("大家好,我是@AfterReturning,他们都秀完了,该我上场了"+result);
    }
}

4、测试代码

package com.dalaoyang;

import com.dalaoyang.serviceImpl.UserServiceImpl;

import com.dalaoyang.utils.DbUtil;
import com.dalaoyang.utils.DbUtilA;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;



@SpringBootTest
public class SpringbootMybatisApplicationTests {

	@Resource
	private UserServiceImpl userService;

	@Test
	public void contextLoads() {
		System.out.println(userService.getUser());
	}

	@Test
	public void setContextLoads() {
		System.out.println(userService.setUser());
	}


}

5、测试结果

我是环绕通知执行
BeforeGetPoint
2022-01-21 13:18:13.287 INFO 3316 — [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting…
2022-01-21 13:18:13.870 INFO 3316 — [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2022-01-21 13:18:13.886 DEBUG 3316 — [ main] c.d.dao.UserMapper.findUserByUsername : Preparing: SELECT * FROM user WHERE user_name=?
2022-01-21 13:18:13.925 DEBUG 3316 — [ main] c.d.dao.UserMapper.findUserByUsername : > Parameters: dalaoyang(String)
2022-01-21 13:18:13.957 DEBUG 3316 — [ main] c.d.dao.UserMapper.findUserByUsername : <== Total: 1
大家好,我是@AfterReturning,他们都秀完了,该我上场了dalaoyang的密码是:1111
AfterGetPoint
执行返回值 : dalaoyang的密码是:1111
getUser方法执行耗时: 733
dalaoyang的密码是:1111
2022-01-21 13:18:14.087 INFO 3316 — [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated…
2022-01-21 13:18:14.142 INFO 3316 — [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.
Process finished with exit code 0


6、编写自定义注解

DataSource

package com.dalaoyang.config;

import com.dalaoyang.utils.DbUtil;

import java.lang.annotation.*;

@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DataSource {
    String value() default DbUtil.DB_MASTER1;
}

DbUtil

package com.dalaoyang.utils;

public class DbUtil {

    /**数据库ds_master1**/
    public static final String DB_MASTER1 = "ds_master1";
    /**数据库ds_master2**/
    public static final String DB_MASTER2 = "ds_master2";


}

7、编写自定义注解方法AOP类

package com.dalaoyang.config;

import com.dalaoyang.utils.DbUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Aspect
@Component
public class AOPAspectAnnotation {

    @Pointcut(value = "@annotation(com.dalaoyang.config.DataSource)")  //注意这里是全文件匹配函数
    public void getPoint() {
    }

    @Before("getPoint()")
    public void setPointAcc1(){
        System.out.println("BeforeGetPoint");
    }

    @Around("getPoint()")
    public Object getDoAround(ProceedingJoinPoint pjp){
        ThreadLocal<Long> startTime = new ThreadLocal<>();
        startTime.set(System.currentTimeMillis());
        System.out.println("我是环绕通知执行");
        Object obj;
        try{
            DataSource dataSource = null;
            MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
            Method method = methodSignature.getMethod();
            dataSource =  method.getAnnotation(DataSource.class);
            if (dataSource==null){
                System.out.println("空值");
                System.out.println(DbUtil.DB_MASTER1);
                obj = pjp.proceed();
                System.out.println("执行返回值 : " + obj);
            }else {
                System.out.println(dataSource.value());
                obj = pjp.proceed();
                System.out.println("执行返回值 : " + obj);
            }
            System.out.println(pjp.getSignature().getName()+"方法执行耗时: " + 
            (System.currentTimeMillis() - startTime.get()));
        } catch (Throwable throwable) {
            obj=throwable.toString();
        }
        return obj;
    }

    @After("getPoint()")
    public void setPointAcc2(){
        System.out.println("AfterGetPoint");
    }

    /**
     * 执行完请求可以做的
     * @param result
     * @throws Throwable
     */
    @AfterReturning(returning = "result", pointcut = "getPoint()")
    public void doAfterReturning(Object result){
        System.out.println("大家好,我是@AfterReturning,他们都秀完了,该我上场了"+result);
    }
}

8、测试代码

package com.dalaoyang;

import com.dalaoyang.serviceImpl.UserServiceImpl;

import com.dalaoyang.utils.DbUtil;
import com.dalaoyang.utils.DbUtilA;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;



@SpringBootTest
public class SpringbootMybatisApplicationTests {

	@Resource
	private UserServiceImpl userService;

	@Test
	public void get1ContextLoads() {
		System.out.println(userService.findUser());
	}
}

9、测试结果

我是环绕通知执行
ds_master2
BeforeGetPoint
2022-01-21 14:31:41.909 INFO 9072 — [main] com.zaxxer.hikari.HikariDataSource :
HikariPool-1 - Starting…
2022-01-21 14:31:42.366 INFO 9072 — [main] com.zaxxer.hikari.HikariDataSource :
HikariPool-1 - Start completed.
2022-01-21 14:31:42.384 DEBUG 9072 — [main] c.d.dao.UserMapper.findUserByUsername : =>
Preparing: SELECT * FROM user WHERE user_name=?
2022-01-21 14:31:42.444 DEBUG 9072 — [main] c.d.dao.UserMapper.findUserByUsername : =>
Parameters: xiaoxiongmao(String)
2022-01-21 14:31:42.478 DEBUG 9072 — [main] c.d.dao.UserMapper.findUserByUsername :
<== Total: 1
大家好,我是@AfterReturning,他们都秀完了,该我上场了xiaoxiongmao的密码是:3333
AfterGetPoint
执行返回值 : xiaoxiongmao的密码是:3333
findUser方法执行耗时: 630
xiaoxiongmao的密码是:3333

10、项目代码

AOP项目链接,方便更加切实了解,在idea导入maven项目即可。

链接:https://pan.baidu.com/s/13dK8cwFw6Z7JKVUAjYmYZw
提取码:rs8m

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叶孤崖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值