Spring AOP 面向切面编程,相信大家都不陌生,它和Spring IOC是Spring赖以成名的两个最基础的功能。在咱们平时的工作中,使用IOC的场景比较多,像咱们平时使用的@Controller、@Service、@Repository、@Component、@Autowired等,这些都和IOC相关。但是,使用AOP的场景却非常少,也就是在事务控制这里使用到了AOP,随着SpringBoot的流行,事务控制这块也不用自己配置了,SpringBoot内部已经给咱们配置好了,我们只需要使用@Transactional这个注解就可以了。

Spring AOP作为Spring的基础功能,大家在学习的时候肯定都学过,但是由于平时使用的比较少,渐渐的就遗忘了,今天我们就再来看看Spring AOP,全面的给大家讲一下,我本人也忘记的差不多了,在面试的时候,人家问我Spring AOP怎么使用,我回答:呵呵,忘得差不多了。对方也是微微一笑,回了一个呵呵。好了,咱们具体看看Spring AOP吧。

Spring AOP解决的问题

面向切面编程,通俗的讲就是将你执行的方法横切,在方法前、后或者抛出异常时,执行你额外的代码。比如:你想要在执行所有的方法前,要验证当前的用户有没有权限执行这个方法。如果没有AOP,你的做法是写个验证用户权限的方法,然后在所有的方法中,都去调用这个公共方法,如果有权限再去执行后面的方法。这样做是可以的,但是显得比较啰嗦,而且硬编码比较多,如果哪个小朋友忘了这个权限验证,那就麻烦了。

现在我们有了AOP,只需要几个简单的配置,就可以在所有的方法之前,去执行我们的验证权限的公共方法。

Sping AOP的核心概念

在AOP当中,核心的术语非常多,有8个,而且理解起来也是晦涩难懂,在这里给大家罗列一下,大家如果感兴趣可以去查阅一下其他的资料。

AOP的8个术语:切面(Aspect)、连接点(Join point)、通知(Advice)、切点(Pointcut)、引入(Introduction)、目标对象(Target object)、AOP代理(AOP proxy)、编织(Weaving)。

在这里,我个人觉得Spring AOP总结成以下几个概念就可以了。

  • 切面(Aspect):在Spring AOP的实际使用中,只是标识的这一段是AOP的配置,没有其他的意义。
  • 切点(Pointcut):就是我们的方法中,哪些方法需要被代理,它需要一个表达式,凡是匹配成功的方法都会执行你定义的通知。
  • 通知(Advice):就是你要另外执行的方法,在前面的例子中,就是权限校验的方法。

好了,知道这几个概念,我个人觉得在平时工作中已经足够了。

Sping AOP的具体配置——注解

我们的实例采用SpringBoot项目搭建,首先我们要把Spring AOP的依赖添加到项目中,具体的maven配置如下:

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

具体的版本我们跟随SpringBoot的版本即可。既然它是个starter,我比较好奇它在配置文件中有哪些配置,我们到application.properties中去看一下,

spring.aop.auto=true
spring.aop.proxy-target-class=true
  • spring.aop.auto:它的默认值是true,它的含义是:Add @EnableAspectJAutoProxy,也就是说,我们在配置类上不再需要标注@EnableAspectJAutoProxy了。这个算是Spring AOP中的一个知识点了,我们重点说一下。

我们在Spring中使用AOP,需要两个条件,第一个,要在我们的项目中引入aspectjweaver.jar,这个,我们在引入spring-boot-starter-aop的时候已经自动引入了。第二个,就是我们我们的配置类中,标注@EnableAspectJAutoProxy 这个注解,如果你使用的是xml的方式,需要你在xml文件中标明<aop:aspectj-autoproxy/>。这样才能在我们的项目使用Spring-AOP。

  • spring.aop.proxy-target-class:AOP代理的实现,这个值默认也是true。它的含义是是否使用CGLIB代理。这也是AOP中的一个知识点。

Spring AOP的代理有两种,一种是标准的JDK动态代理,它只能代理接口,也即是我们在使用的时候,必须写一个接口和实现类,在实现类中写自己的业务逻辑,然后通过接口实现AOP。另外一种是使用CGLIB 代理,它可以实现对类的代理,这样我们就不用去写接口了。

Spring AOP默认使用的是JDK动态代理,只能代理接口,而我们在开发的时候为了方便,希望可以直接代理类,这就需要引入CGLIB ,spring.aop.proxy-target-class默认是true,使用CGLIB,我们可以放心大胆的直接代理类了。

通过前面的步骤,我们已经可以在项目中使用Spring AOP代理了,下面我们先创建个Service,再写个方法,如下:

@Service
public class MyService { public void gotorun() {
System.out.println("我要去跑步!");
} }

我们写了个“我要去跑步”的方法,然后再通过AOP,在方法执行之前,打印出“我穿上了跑鞋”。下面重点看一下这个AOP代理怎么写,

@Component
@Aspect
public class MyAspect { @Pointcut("execution(public * com.example.springaopdemo.service.*.*(..))")
private void shoes() {} @Before("com.example.springaopdemo.aspect.MyAspect.shoes()")
public void putonshoes() {
System.out.println("我穿上跑步鞋。");
}
}

首先,要创建一个切面,我们在类上使用@Aspect注解,标识着这个类是一个切面,而@Component注解是将这个类实例化,这样这个切面才会起作用。如果只有@Aspect而没有被Spring实例是不起作用的。当然Spring实例化的方法有很多,不一定就非要使用@Component。

再来看看切点的声明,切点的作用是匹配哪些方法要使用这个代理,我们使用@Pointcut注解。@Pointcut注解中有个表达式就是匹配我们的方法用到,它的种类也有很多,这里我们给大家列出几个比较常用的execution表达式吧,

execution(public * *(..))      //匹配所有的public方法
execution(* set*(..)) //匹配所有以set开头的方法
execution(* com.xyz.service.AccountService.*(..)) //匹配所有AccountService中的方法
execution(* com.xyz.service.*.*(..)) //匹配所有service包中的方法
execution(* com.xyz.service..*.*(..)) //匹配所有service包及其子包中的方法

示例中,我们匹配的是service包中的所有方法。

有没有同学比较好奇@Pointcut下面的那个方法?这个方法到底有没有用?方法中如果有其他的操作会不会执行?答案是:方法里的内容不会被执行。那么它有什么用呢?它仅仅是给@Pointcut一个落脚的地方,仅此而已。但是,Spring对一个方法也是有要求的,这个方法的返回值类型必须是void。原文是这么写的:**

the method serving as the pointcut signature must have a void return type

最后我们再来看看通知,通知的种类有5种,分别为:

  • @Before:前置通知,在方法之前执行;
  • @AfterReturning:返回通知,方法正常返回以后,执行通知方法;
  • @AfterThrowing:异常通知,方法抛出异常后,执行通知方法;
  • @After:也是返回通知,不管方法是否正常结束,都会执行这个方法,类似于finally;
  • @Around:环绕通知,在方法执行前后,都会执行通知方法;

在示例中,使用的是@Before前置通知,我们最关心的是@Before里的内容:

@Before("com.example.springaopdemo.aspect.MyAspect.shoes()")
public void putonshoes() {
System.out.println("我穿上跑步鞋。");
}

@Before里的内容是切点的方法,也就是我们定义的shoes()方法。那么所有匹配了shoes()切点的方法,都会执行@Before这个注解的方法,也就是putonshoes()。

在@Before里除了写切点的方法,还可以直接写切点表达式,例如:

@Before("execution(public * com.example.springaopdemo.service.*.*(..))")
public void putonshoes() {
System.out.println("我穿上跑步鞋。");
}

如果我们使用这种表达式的写法,就可以省去前面的@Pointcut了,这种方法还是比较推荐的。我们再写个测试类运行一下,看看效果吧,

@SpringBootTest
class SpringAopDemoApplicationTests {
@Autowired
private MyService myService; @Test
public void testAdvice() {
myService.gotorun();
}
}

运行结果如下:

我穿上跑步鞋。
我要去跑步!

没有问题,在执行“我要去跑步”之前,成功的执行了“我穿上跑步鞋”的方法。

好了,今天先到这里,下一篇我们看看如何使用xml的方式配置Spring AOP。

温故知新——Spring AOP的更多相关文章

  1. 温故知新——Spring AOP(二)

    上一篇我们介绍Spring AOP的注解的配置,也叫做Java Config.今天我们看看比较传统的xml的方式如何配置AOP.整体的场景我们还是用原来的,"我穿上跑鞋",&quo ...

  2. 学习AOP之深入一点Spring Aop

    上一篇<学习AOP之认识一下SpringAOP>中大体的了解了代理.动态代理及SpringAop的知识.因为写的篇幅长了点所以还是再写一篇吧.接下来开始深入一点Spring aop的一些实 ...

  3. 学习AOP之认识一下Spring AOP

    心碎之事 要说知道AOP这个词倒是很久很久以前了,但是直到今天我也不敢说非常的理解它,其中的各种概念即抽象又太拗口. 在几次面试中都被问及AOP,但是真的没有答上来,或者都在面上,这给面试官的感觉就是 ...

  4. spring aop

    什么是AOP AOP(Aspect-OrientedProgramming,面向方面编程),它利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将 ...

  5. spring aop注解方式与xml方式配置

    注解方式 applicationContext.xml 加入下面配置 <!--Spring Aop 启用自动代理注解 --> <aop:aspectj-autoproxy proxy ...

  6. 基于Spring AOP的JDK动态代理和CGLIB代理

    一.AOP的概念  在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的 ...

  7. Spring AOP详解

    一.前言 在以前的项目中,很少去关注spring aop的具体实现与理论,只是简单了解了一下什么是aop具体怎么用,看到了一篇博文写得还不错,就转载来学习一下,博文地址:http://www.cnbl ...

  8. Spring AOP实例——异常处理和记录程序执行时间

    实例简介: 这个实例主要用于在一个系统的所有方法执行过程中出线异常时,把异常信息都记录下来,另外记录每个方法的执行时间. 用两个业务逻辑来说明上述功能,这两个业务逻辑首先使用Spring AOP的自动 ...

  9. 从零开始学 Java - Spring AOP 实现用户权限验证

    每个项目都会有权限管理系统 无论你是一个简单的企业站,还是一个复杂到爆的平台级项目,都会涉及到用户登录.权限管理这些必不可少的业务逻辑.有人说,企业站需要什么权限管理阿?那行吧,你那可能叫静态页面,就 ...

随机推荐

  1. 高阶NumPy知识图谱-《利用Python进行数据分析》

    所有内容整理自<利用Python进行数据分析>,使用MindMaster Pro 7.3制作,emmx格式,源文件已经上传Github,需要的同学转左上角自行下载或者右击保存图片. 其他章 ...

  2. #define IOFFSETOF(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

    #include <iostream> #define IOFFSETOF(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) usi ...

  3. Idea风格的快捷键

    在使用IntelliJ IDEA时,是可以定义快捷键风格的:File --> Setting --> Keymap 里进行选择,因为我以前用Eclipse开发,后来换成Idea有2年的时间 ...

  4. 【python设计模式-创建型】工厂方法模式

    工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 在工厂模式中,我们在创建对象时不会对客户端暴露创建逻 ...

  5. Pytorch Autograd (自动求导机制)

    Pytorch Autograd (自动求导机制) Introduce Pytorch Autograd库 (自动求导机制) 是训练神经网络时,反向误差传播(BP)算法的核心. 本文通过logisti ...

  6. NCoreCoder.Aop详解

    于今天,功能终于完善度到比较满意的程度了 准备好好写一篇文章,而不是之前的流水账,分享一下最近这些天的踩坑 一开始AOP选的微软提供的DispatchProxy 关于这个,有大佬的文章,可以看看,了解 ...

  7. springboot 使用DruidDataSource 数据源

    一.添加依赖 <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</art ...

  8. vue实现自定义表格列

    在我们开发PC端的项目使用表单时,尤其是crm系统,应该经常会遇到这样的需求, 用户需要根据设置来自定义显示列. 查了element的官方文档, 并没有此类组件, 所以手动封装了一个简单的组件, 希望 ...

  9. C#LeetCode刷题之#744-寻找比目标字母大的最小字母(Find Smallest Letter Greater Than Target)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/4001 访问. 给定一个只包含小写字母的有序数组letters 和 ...

  10. C#设计模式之7-桥接模式

    桥接模式(Bridge Pattern) 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/401 访问. 桥接模式属于结构 ...