spring boot AOP练习 @Aspect

2022-07-27,,,

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动态代理; 缺点:会有一点影响性能
 */
@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())
        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老同志发言完成,恭喜大家获取技能闪电五连变
----------------分界线--------------------
前置环绕:运行......
老马说:.......
后置环绕:运行......

看代码来说如果指定了参数和指定了运行的bean ,那么这个切面只有相应的bean才能被调用
如果只指定了参数和无视参数,指定了参数的优先级高.

本文地址:https://blog.csdn.net/qq_44738044/article/details/109994857

《spring boot AOP练习 @Aspect.doc》

下载本文的Word格式文档,以方便收藏与打印。