前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring AOP的简单应用

Spring AOP的简单应用

作者头像
每天学Java
发布2020-06-02 10:06:28
3260
发布2020-06-02 10:06:28
举报
文章被收录于专栏:每天学Java每天学Java每天学Java

在各种业务场景中,我们可会有打印日志这种语句,通常为了方便我们直接写在业务逻辑的代码中。实际上和业务无关的代码我们也放入到业务逻辑中,会带来了较强的侵入性编码。通常来说,日志和业务代码应该是分离的,而Spring AOP能很好的实现日志和业务代码的分离,当然Spring AOP的作用不仅仅是用来打印日志的,还可以用来做权限控制,缓存等等......

AOP也叫做面向切面编程(Aspect-Oriented Programming),它的核心是动态代理,了解过设计模式的小伙伴应该都知道代理模式,代理模式包含两大类:静态代理和动态代理。静态代理这里就不说了;动态代理实现方法我知道的有两种:JDK自带的动态代理和CGLIB的动态代理,JDK自带的动态代理基于反射,所以效率相对低,而且只能代理实现接口的对象。CGLIB的动态代理基于字节码实现(这比反射效率高)而且可以代理没有实现接口的对象,但是不能代理final方法。

这篇文章我们先简单实现利用AOP实现日志打印,然后再看相关注解含义。

相关文章: 代理模式

Spring Boot的搭建

01

利用AOP实现日志打印

项目中我们首先导入相关依赖:

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

题外话:我是真的觉得现在SpringBoot集成其他框架很简单,我在公司项目上,想要集成AOP做自己开发代码的日志监控,先要导入六七个jar包,然后写(抄)Spring的配置文件,修改(抄)web.xml文件,然后还失败了,因为配置AOP之后,初始化容器报错说不支持XML Schema,只能用XML DTD,最后东改西改的成功启动了,但是AOP还没有集成成功,有这方面有经验的小伙伴请留言指导(我对配置文件基本是完全不懂)。

当我们导入完依赖之后,我们就可以写自己的Aspect类,用于监控方法。

package xcx.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * @Auther: chenlong
 * @Date: 2019/3/2 16:19
 * @Description:
 */

@Aspect
@Component
public class MyAspect {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Pointcut("execution(* xcx.request.controller.*.*(..))")
    public void logging() {
    }

    @Before(value = "logging() ")
    public void logStart(JoinPoint joinPoint) {
        logger.info(joinPoint.getSignature().getName() + "运行,参数列表是: {" + Arrays.asList(joinPoint.getArgs()) + "}");
    }

    @After(value = "logging()")
    public void logEnd(JoinPoint joinPoint) {
        System.out.println(joinPoint.getSignature().getName() + "结束...");
    }

    @AfterReturning(value = "logging()", returning = "result")
    public void logReturn(JoinPoint joinPoint, Object result) {
        System.out.println(joinPoint.getSignature().getName() + "正常结束,结果是: {" + result + "}");
    }

    @AfterThrowing(value = "logging()", throwing = "e")
    public void logException(JoinPoint joinPoint, Exception e) {
        System.out.println(joinPoint.getSignature().getName() + "异常,异常信息: {" + e.getMessage() + "}");
    }

}

然后.....就没了,我们启动项目然后访问xcx.request.controller下的API就会打印相应日志了:是不是很简单,这样就成功的将业务逻辑和日志打印成功分离,我这里为了测试将execution配置范围比较大,大家可以指定到某个具体的方法,进行单独监控。

下面我们再来看看这些注解有什么含义

02

AOP的术语

通知(Advice):

Spring中的切面一共提供5种通知的类型:

  前置通知(Before)   后置通知(After)   返回通知(After-Running)   异常通知(After-throwing)   环绕通知(Around)

前面4个较为容易理解,例如“前置通知”,我们通常在一个方法的第一句打印出传入的方法参数,此时就可以使用前置通知在方法调用前打印出传入的参数。对于“后置通知”实际是“返回通知”和“异常通知”的并集,返回通知表示程序正确运行返回后执行,异常通知表示程序不正常运行抛出异常时执行,而后置通知则不论程序是否正确运行,一旦离开方法就会执行。

环绕通知最为强大,它包裹了被通知的方法,可同时定义前置通知和后置通知。

切点(Pointcut):

通知定义了何时工作以及工作内容,切点则定义了在何处工作,也就是在哪个方法应用通知。要表达出在哪个方法中运用通知,这需要用到切点表达式。Spring AOP借助AspectJ(另一种AOP实现)的切点表达式来确定通知被应用的位置,虽然是借助但并不支持所有AspectJ的所有切点指示器而仅仅是其一个子集,这其中最为常用的就是execution切点指示器,表示执行。就如同上述代码:

 @Pointcut("execution(* xcx.request.controller.*.*(..))")

execution()是最常用的切点函数,其语法如下所示:

整个表达式可以分为五个部分:

1、execution(): 表达式主体。

2、第一个*号:表示返回类型,*号表示所有的类型。

3、包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,com.sample.service.impl包、子孙包下所有类的方法。

4、第二个*号:表示类名,*号表示所有的类。

5、*(..):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数。

到这里就引入Spring AOP到项目中,集成很简单,但是明白原理才是最重要的,在文章的开始我大致的说了AOP是如何实现的,但是很浅显,下篇文章我们再详细的看一下动态代理。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-03-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 每天学Java 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档