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. C/C++编程笔记:C语言贪吃蛇源代码控制台(二),分数和食物!

    接上文<C/C++编程笔记:C语言贪吃蛇源代码控制台(一),会动的那种哦!>如果你在学习C语言开发贪吃蛇的话,零基础建议从上一篇开始哦!接下来正式开始吧! 三.蛇的运动 上次我已经教大家画 ...

  2. luogu P3403 跳楼机 同余最短路

    LINK:跳楼机 很早之前就想学的一个东西.发现这个东西果然神奇. 我们要找到 所有的 w满足 \(w=1+ax+by+cz\).且 \(1\leq w\leq h\) 暴力枚举是不行的. 做法是这样 ...

  3. 牛客练习赛60 D 斩杀线计算大师

    LINK:斩杀线计算大师 给出a,b,c三个值 求出 ax+by+cz=k的x,y,z的正整数解 保证一定有解. 考虑两个数的时候 ax+by=k 扩展欧几里得可以解决. 三个数的时候 一个暴力的想法 ...

  4. react-ts模板/脚手架

    react-ts-template 脚手架 使用 npm i -g maple-react-cli maple-react-cli init 选择模板 'react-ts-template' 输入自定 ...

  5. Java对象(创建过程、内存布局、访问方法)

    (Java 普通对象.不包括数组.Class 对象等.) ​ 对象创建过程 类加载 遇到 new 指令时,获取对应的符号引用,并检查该符号引用代表的类是否已被初始化.如果没有就进行类加载. 分配内存 ...

  6. 在新的线程中使用session 出现的问题

    Exception in thread "Thread-15" java.lang.IllegalStateException: No thread-bound request f ...

  7. github开源文章生成pdf

    最近需要研究ELK,然后在网上发现了有本书写的不错,然后搜到是在 github 上开源过的.这本书的时间有点久了,就想通过源码自己来生成一个 pdf 我使用的是 ubuntu 系统 step1:安装 ...

  8. 018_go语言中的结构体

    代码演示 package main import "fmt" type person struct { name string age int } func main() { fm ...

  9. Python 创建用户界面之 PyQt5 的使用

    之前给大伙介绍了下 tkinter,有朋友希望小帅b对其它的 Python  GUI 框架也说道说道,那么今天就来说说 PyQt5 如何创建用户界面.   很多人学习python,不知道从何学起.很多 ...

  10. 17、Observer 观察者模式

    以一个实例给大家引入观察者,大家多多少少都写过html或者java中的swing.我们定义一个按钮,给他增加一个点击事件,那么这个方法是怎么被触发到呢,对了,就是利用了观察者设计模式 观察者模式 当对 ...