AOP常见使用场景和代码实现

AOP常见使用场景和代码实现

前言:
本文没有关于AOP的概念的介绍,这些官网上和很多博客都已经做过了。直接解决的是我们在日常开发中,需要使用AOP的部分场景以及如何使用。并附上自己写的代码。希望你看到这篇文章的时候,对你能有所帮助。

开发中可能用到AOP的场景:

如果让我们在现有的代码上加上日志功能,便于后期排错。现在有两种解决方案:
第一:就是在代码上直接加上日志(代码量比较多的时候,非常痛苦,而且都是同样的工作)
第二:就是使用AOP来实现在(基于注解)

注: AOP的底层用的是动态代理,JDK代理和CGlib,两者的直观区别在于 JDK代理需要接口和接口实现,CGlib代理不需要。AOP根据我们的代码实现了动态的选择。

@Service
public class CalcServiceImpl implements CalcService {
    @Override
    @ApiOperation(value = "计算器加法")
    public Integer add(Integer i, Integer j) {
        return i+j;
    }
    @Override
    @ApiOperation(value = "计算器减法")
    public Integer reduce(Integer i, Integer j) {
        return i-j;
    }
    @Override
    @ApiOperation(value = "计算器乘法")
    public Integer ride(Integer i, Integer j) {
        return i*j;
    }
    @Override
    @ApiOperation(value = "计算器除法")
    public Integer except(Integer i, Integer j) throws Exception {
        if(j==0){
            throw new Exception(j+":不能为0");
        }
        return i/j;
    }

直接上AOP实现:

1、新建项目引入依赖

新建一boot项目,引入AOP的依赖 :aspectjweaver,spring-aspects
引入了swagger 便于演示获取注解参数值。

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--Aop的依赖:aspectjweaver,spring-aspects-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>
        <!-- 逆向工程swagger整合 start -->
        <dependency>
            <groupId>com.spring4all</groupId>
            <artifactId>swagger-spring-boot-starter</artifactId>
            <version>1.9.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>com.github.misterchangray.mybatis.generator.plugins</groupId>
            <artifactId>myBatisGeneratorPlugins</artifactId>
            <version>1.2</version>
        </dependency>
        <!-- 逆向工程swagger整合 end -->
    </dependencies>

2、建立xml文件

必须在xml中,开启包扫描 和 开启AOP功能,否则不会生效。

	<!--扫描包:扫描类中的所有注解,不扫描注解不会生效-->
    <context:component-scan base-package="com.example.demo"></context:component-scan>
    <!--因为使用过的是注解方式的Aop,所以要开启注解Aop功能-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

3、创建一个增强类

@Aspect’ :声明切面
@Component :声明组件 注册到ioc容器中

@Aspect
@Component
@Slf4j
public class LogUtil {
    //可以采用声明切点的方式让其他通知引用,这样可复用性更强。
    @Pointcut("execution(* com.example.demo.service..*.*(..)))")
    public void pointcut(){
    }
    //前置通过
    @Before("pointcut()")
    //JoinPoint:获取切点的方法和参数
    public static void before(JoinPoint joinPoint){
        //获取方法名
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        System.out.println(methodName+":方法运行");
        log.info("方法参数是:"+Arrays.asList(args).toString());
        System.out.println("方法参数是:"+Arrays.asList(args).toString());
    }
    //后置通知
    //通过@annotation 值是方法上的注解名称(首字母小写),可以挺过.value方法获取该注解的value
    @After("execution(* com.example.demo.service..*.*(..)) && @annotation(apiOperation)")
    public static void after(JoinPoint joinPoint, ApiOperation apiOperation){
        System.out.println("方法运行后");
        System.out.println("获取方法上注解名称:"+ apiOperation.value());
    }
    //后置异常通知
    @AfterThrowing(value = "execution(* com.example.demo.service..*.*(..))",
    throwing = "ex")
    public static void afterException(Exception ex){
        //捕获异常栈信息
        StringWriter sw = new StringWriter();
        ex.printStackTrace(new PrintWriter(sw,true));
        System.out.println("后置异常通知:"+sw.getBuffer().toString());
    }
    //后置返回通知
    @AfterReturning(value = "execution(* com.example.demo.service..*.*(..))",
            returning = "returnValue")
    public static void afterEnd(Object returnValue){
        System.out.println("方法结束,返回值是:"+ returnValue);
    }
    //环绕通知
    @Around(value = "pointcut()" )
    public Object arround (ProceedingJoinPoint joinPoint){
        //获取方法名
        String methodName = joinPoint.getSignature().getName();
        //获取参数
        Object[] args = joinPoint.getArgs();
        Object returnValue = null;
        try {
            System.out.println("环绕:::前置通知:"+methodName+"方法执行,参数:"+Arrays.asList(args));
            joinPoint.proceed();
            System.out.println("环绕:::后置通知:"+methodName+"方法执行,参数:"+Arrays.asList(args));
        } catch (Throwable throwable) {
            System.out.println("环绕:::异常通知:"+throwable);
        }finally {
            System.out.println("环绕:::返回通知:"+returnValue);
        }
    return returnValue;
    }

基于注解的ioc比较简单,只需要了解注解和想对应每个注解的每个参数就可以了。
"execution( com.example.demo.service….(…)) && @annotation(apiOperation)"*
这里的切点表达式需要解释一下:
第一个== * :代表的是方法的声明类型和返回值类型默认是(public void)*代表所有声明类型和返回值类型
第二个:com.example.demo.service… 需要操作的包一般是写到接口这一层,因为spring会自动通过接口查找接口实现,这个是关于spring的底层实现。后面的点点,代表的是他他下面的子包和子孙包。
.(…)) == 代表所有的类所有的的所有方法以及方法的所有参数。
注解的方式,还是很简单易懂的,如果有兴趣的话可以敲一下代码,实践出真知。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值