欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

spring boot AOP练习 @Aspect

程序员文章站 2022-06-16 16:09:18
spring boot AOP练习 @Aspect环境 org.springframework.boot spring-boot-starter-aop ...

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;
    }
}

spring boot AOP练习 @Aspect项目结构

@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