spring boot AOP练习 @Aspect

spring boot AOP练习 @Aspect

环境

		<!--  主要依赖     -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

开启配置

/**
 * @author smxr
 * @date 2020/11/19
 * @time 11:11
 * @EnableAspectJAutoProxy(proxyTargetClass = true)
 * 这个为true时,则会使用 cglib 的动态代理方式;缺点:拓展类的实例用final修饰时,则无法进行织入
 * 默认使用的是jdk动态代理; 缺点:会有一点影响性能
 * 12/23:默认(proxyTargetClass = true不使用)时,当动态代理的对象是接口时,会使用jdk动态代理,如果对象是Class时使用cglib动态代理
 */
@Configuration
@EnableAspectJAutoProxy
public class ConfigBean {

    @Conditional(UserConditional.class)
    @Bean
    public User user(){
        System.out.println("张三加载中...........");
        User user = new User();
        user.setUserName("张三");
        return user;
    }
    @Conditional(UserConditional2.class)
    @Bean
    public User user2(){
        System.out.println("李四加载中...........");
        User user = new User();
        user.setUserName("李四");
        return user;
    }
}

在这里插入图片描述项目结构

@Aspect 切面类

/**
 * @author smxr
 * @date 2020/11/23
 * @time 10:33
 */
@Aspect
@Component
public class AspectUserService {
//    @Pointcut("execution( public * com.redis.service.impl.UserServiceImpl.sleep(..))")
    private void PointCut(){}
    @Before("execution(public * com.redis.service.UserService.sleep(..))")
    public void sleepBefore(JoinPoint joinPoint){
      //  System.out.println(joinPoint.toString());//输出结果:execution(void com.redis.service.impl.UserServiceImpl.sleep())
      // MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
       //String[] params = methodSignature.getParameterNames();// 获取参数名称
       //Object[] args = joinPoint.getArgs();// 获取参数值
        System.out.println("前置拦截开始了");//2
    }
    @After("execution(public * com.redis.service.UserService.sleep(..))")
    public void sleepAfter(JoinPoint joinPoint){
        System.out.println("后置拦截开始了");//4
    }
    @AfterReturning("execution(public * com.redis.service.UserService.sleep(..))")
    public void sleepAfterReturning(JoinPoint joinPoint){
        System.out.println("完成拦截开始了");//3
    }
    @AfterThrowing("execution(public * com.redis.service.UserService.sleep(..))")
    public void sleep(JoinPoint joinPoint){
        System.out.println("异常拦截开始了");
    }
    @Around("execution(public * com.redis.service.UserService.sleep(..))")
    public void sleepAround(ProceedingJoinPoint proceedingJoinPoint){
        try {
            System.out.println("前置环绕:运行......");//1
            proceedingJoinPoint.proceed();
            System.out.println("后置环绕:运行......");//5
        } catch (Throwable throwable) {
            System.out.println("环绕:运行异常......");
        }
    }
}

相关接口和实现类

/**
 * @author smxr
 * @date 2020/11/23
 * @time 10:20
 */
public interface UserService {
    public void eat();
    public void sleep();
    public void corporate_slave();
    public void speak(User user);
}

import com.redis.pojo.User;
import com.redis.service.UserService;
import org.springframework.stereotype.Service;

/**
 * @author smxr
 * @date 2020/11/23
 * @time 10:25
 */
@Service
public class UserServiceImpl implements UserService {
    @Override
    public void eat() {
        System.out.println("要去吃饭了......");
    }

    @Override
    public void sleep() {
        System.out.println("终于到了放松的时候了........");
    }

    @Override
    public void corporate_slave() {
        System.out.println("要去工作了.........");
    }

    @Override
    public void speak(User user) {
        System.out.println(user.getUserName()+"说:.......");
    }
}

测试及结果

@SpringBootTest
class SpringbootRedisApplicationTests {
    @Autowired
    UserServiceImpl userService;
    @Test
    void AOPTest(){
        userService.sleep();
    }
     -----------------------------------------------
前置环绕:运行......
前置拦截开始了
终于到了放松的时候了........
完成拦截开始了
后置拦截开始了
后置环绕:运行......

不知道有没有错,反正跑出来的顺序就这样的.

切面有参的AOP练习

AspectUserService.class

    //不关注 参数  
    @Around("execution(public * com.redis.service.UserService.speak(..))")
    public void speakAround(ProceedingJoinPoint proceedingJoinPoint){
        try {
            System.out.println("前置环绕:运行......");
            proceedingJoinPoint.proceed();
            System.out.println("后置环绕:运行......");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

    //
    /*
    * 关注 参数
    * && args(user) 指定参数;要传入的参数
    * && bean(userServiceImpl) 指定要使用的容器组件名;即这个指定的(userServiceImpl)组件bean去调用,才能生效.
    */
    @Around("execution(public * com.redis.service.UserService.speak(..)) && args(user)")
    public void speakAround(ProceedingJoinPoint proceedingJoinPoint,User user){
        try {
            if (user.getUserAge()==69){
                System.out.println(user.getUserAge()+"老同志即将发言,请注意听讲!如果你大意了,就没有闪了");
            }else if (user.getUserAge()>69){
                System.out.println(user.getUserAge()+"老同志即将发言,请注意听讲!");
            }else {
                System.out.println(user.getUserName()+"的前置环绕即将说话:请注意听讲");
            }
            proceedingJoinPoint.proceed();
            if (user.getUserAge()==69){
                System.out.println(user.getUserAge()+"老同志发言完成,恭喜大家获取技能闪电五连变");
            }else {
                System.out.println(user.getUserName()+"的后置环绕完成!");
            }
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

测试代码

    @Test
    void AOPTest1(){
        User user3 = new User();
        user3.setUserName("马老师");
        user3.setUserAge(69);
        userService.speak(user3);
        System.out.println("----------------分界线--------------------");
        User user4 = new User();
        user4.setUserName("老马");
        user4.setUserAge(80);
        userService.speak(user4);
    }
前置环绕:运行......
69老同志即将发言,请注意听讲!如果你大意了,就没有闪了
马老师说:.......
69老同志发言完成,恭喜大家获取技能闪电五连变
后置环绕:运行......
----------------分界线--------------------
前置环绕:运行......
80老同志即将发言,请注意听讲!
老马说:.......
老马的后置环绕完成!
后置环绕:运行......
    //要注意指定的 && bean(userServiceImpl)  否则重新注入一个新的userServiceImpl2 是不能调用的
    @Autowired
    UserServiceImpl userService;

还是看下案例吧!
新注入一个userService2

@Configuration
@EnableAspectJAutoProxy
public class ConfigBean {

    @Conditional(UserConditional.class)
    @Bean
    public User user(){
        System.out.println("张三加载中...........");
        User user = new User();
        user.setUserName("张三");
        return user;
    }
    @Conditional(UserConditional2.class)
    @Bean
    public User user2(){
        System.out.println("李四加载中...........");
        User user = new User();
        user.setUserName("李四");
        return user;
    }
    @Bean
    public UserServiceImpl userService2(){
        UserServiceImpl userService2 = new UserServiceImpl();
        return userService2;
    }
}

原来的service 声明bean名字


/**
 * @author smxr
 * @date 2020/11/23
 * @time 10:25
 */
@Service(value = "userService")
public class UserServiceImpl implements UserService {
    @Override
    public void eat() {
        System.out.println("要去吃饭了......");
    }

    @Override
    public void sleep() {
        System.out.println("终于到了放松的时候了........");
    }

    @Override
    public void corporate_slave() {
        System.out.println("要去工作了.........");
    }

    @Override
    public void speak(User user) {
        System.out.println(user.getUserName()+"说:.......");
    }
}

测试及结果

@SpringBootTest
class SpringbootRedisApplicationTests {
    @Autowired
    UserServiceImpl userService;
    @Autowired
    UserServiceImpl userService2;

    @Test
    void AOPTest1(){
        User user3 = new User();
        user3.setUserName("马老师");
        user3.setUserAge(69);
        userService.speak(user3);
        System.out.println("----------------分界线--------------------");
        User user4 = new User();
        user4.setUserName("老马");
        user4.setUserAge(80);
        userService2.speak(user4);
    }

}

69老同志即将发言,请注意听讲!如果你大意了,就没有闪了
马老师说:.......
69老同志发言完成,恭喜大家获取技能闪电五连变
----------------分界线--------------------
老马说:.......

上面的我把 无参的那个给注释掉了, 下面解开注释在跑一次

    //不关注 参数
    @Around("execution(public * com.redis.service.UserService.speak(..))")
    public void speakAround(ProceedingJoinPoint proceedingJoinPoint){
        try {
            System.out.println("前置环绕:运行......");
            proceedingJoinPoint.proceed();
            System.out.println("后置环绕:运行......");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

    //
    /*
    * 关注 参数
    * && args(user) 指定参数;要传入的参数
    * && bean(userServiceImpl) 指定要使用的容器组件名;即这个指定的(userServiceImpl)组件bean去调用,才能生效.
    */
    @Around("execution(public * com.redis.service.UserService.speak(..)) && args(user)&& bean(userService)")
    public void speakAround(ProceedingJoinPoint proceedingJoinPoint,User user){
        try {
            if (user.getUserAge()==69){
                System.out.println(user.getUserAge()+"老同志即将发言,请注意听讲!如果你大意了,就没有闪了");
            }else if (user.getUserAge()>69){
                System.out.println(user.getUserAge()+"老同志即将发言,请注意听讲!");
            }else {
                System.out.println(user.getUserName()+"的前置环绕即将说话:请注意听讲");
            }
            proceedingJoinPoint.proceed();
            if (user.getUserAge()==69){
                System.out.println(user.getUserAge()+"老同志发言完成,恭喜大家获取技能闪电五连变");
            }else {
                System.out.println(user.getUserName()+"的后置环绕完成!");
            }
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

测试和结果

69老同志即将发言,请注意听讲!如果你大意了,就没有闪了
前置环绕:运行......
马老师说:.......
后置环绕:运行......
69老同志发言完成,恭喜大家获取技能闪电五连变
----------------分界线--------------------
前置环绕:运行......
老马说:.......
后置环绕:运行......

看代码来说如果指定了参数(&&args)和指定了运行的bean(&&bean) ,那么这个切面只有相应的bean才能被调用;
没有指定参数(&&args)和运行的bean(&&bean),那么只要这个实例被调用就,都会执行切面;
如果两个同时存在,那么都会被执行,有参的优先级较高,先执行将包含无参的;

挺好奇的,上面的代码他们的@Before,@After,@AfterReturning,他们什么时候执行?

先改下代码,新增

    @Before("execution(public * com.redis.service.UserService.speak(..))")
    public void speakBefore(JoinPoint joinPoint){
        System.out.println("前置拦截开始了");
    }
    @After("execution(public * com.redis.service.UserService.speak(..))")
    public void speakAfter(JoinPoint joinPoint){
        System.out.println("后置拦截开始了");
    }
    @AfterReturning("execution(public * com.redis.service.UserService.speak(..))")
    public void speakAfterReturning(JoinPoint joinPoint){
        System.out.println("完成拦截开始了");
    }

测试及结果

    @Test
    void AOPTest1(){
        User user3 = new User();
        user3.setUserName("马老师");
        user3.setUserAge(69);
        userService.speak(user3);
        System.out.println("----------------分界线--------------------");
        User user4 = new User();
        user4.setUserName("老马");
        user4.setUserAge(80);
        userService2.speak(user4);
    }

前置环绕:运行......
69老同志即将发言,请注意听讲!如果你大意了,就没有闪了
前置拦截开始了
马老师说:.......
完成拦截开始了
后置拦截开始了
69老同志发言完成,恭喜大家获取技能闪电五连变
后置环绕:运行......
----------------分界线--------------------
前置环绕:运行......
前置拦截开始了
老马说:.......
完成拦截开始了
后置拦截开始了
后置环绕:运行......

阿狸! 什么鬼 ? 我注释掉新加在跑一次

前置环绕:运行......
69老同志即将发言,请注意听讲!如果你大意了,就没有闪了
马老师说:.......
69老同志发言完成,恭喜大家获取技能闪电五连变
后置环绕:运行......
----------------分界线--------------------
前置环绕:运行......
老马说:.......
后置环绕:运行......

干掉代码在跑,加上代码在跑

69老同志即将发言,请注意听讲!如果你大意了,就没有闪了
前置环绕:运行......
前置拦截开始了
马老师说:.......
完成拦截开始了
后置拦截开始了
后置环绕:运行......
69老同志发言完成,恭喜大家获取技能闪电五连变
----------------分界线--------------------
前置环绕:运行......
前置拦截开始了
老马说:.......
完成拦截开始了
后置拦截开始了
后置环绕:运行......

反正挺好玩的! 我也没搞清楚 倒是是无参的先还是有参的先,
或者它们本来就是不分先后的,也许就不能一块用;
不过其他三个倒是挺正常的;先@Before,在@AfterReturning,最后@After

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Spring Boot AOPAspect-Oriented Programming)是Spring Boot框架中的一个特性,它允许开发者对应用程序的不同模块进行横切关注点的编程。AOP可以用于处理日志记录、事务管理、安全性等方面的交叉功能,而不需要修改原始代码。 在Spring Boot中使用AOP,你需要以下几个步骤: 1. 添加依赖:在你的项目中添加Spring AOP的依赖,例如在pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> ``` 2. 创建切面类:创建一个Java类,用于定义切面逻辑。这个类需要使用`@Aspect`注解进行标记,并且可以使用其他注解来定义切点和通知。 ```java @Aspect @Component public class LoggingAspect { @Before("execution(public * com.example.demo.*.*(..))") public void beforeAdvice(JoinPoint joinPoint) { // 在方法执行之前执行的逻辑 // 可以用来记录日志或者进行权限验证等操作 } // 其他通知方法,如@After、@AfterReturning、@AfterThrowing等 } ``` 3. 配置切面:在配置类或者启动类上使用`@EnableAspectJAutoProxy`注解启用AOP自动代理。 ```java @SpringBootApplication @EnableAspectJAutoProxy public class DemoApplication { // ... } ``` 以上就是使用Spring Boot AOP的基本步骤。你可以根据需要在切面类中定义不同的通知方法,并在切点上指定具体的拦截规则。这样,在程序执行到切点时,AOP会自动调用相应的通知方法。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值