AOP
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
AOP相关概念
- Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在 spring 中,这些点指的是方法,因为 spring 只支持方法类型的连接点。
- Pointcut(切入点):所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义。
- Advice(通知/增强):所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知。 通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。
- Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下, Introduction 可以在运行期为类动态地添加一些方
法或 Field。 - Target(目标对象):代理的目标对象。
- Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装载期织入。
- Proxy(代理):一个类被 AOP 织入增强后,就产生一个结果代理类。
- Aspect(切面):是切入点和通知(引介)的结合。
maven依赖
添加dependency
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.5</version> </dependency>
基于xml
配置约束文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
- 使用
aop:config
标签表明开始AOP的配置 使用
aop:aspect
标签表明配置切面id
属性:给切面提供唯一标识ref
属性:制定通知类的beanId
在
aop:aspect
标签内部使用对应标签来配置通知的类型aop:brfore
:表示前置通知aop:after
:表示最终通知aop:after-running:表示后置通知
aop:after-throwing
:表示异常通知pointcut
属性:用于指定切入点表达式,只对业务层哪些方法增强method
属性:用于指定哪个方法对应的相应的通知- 异常通知后后置通知只会执行一个
aop:pointcut
标签:用来配置切入点表达式,id
属性为唯一标志,expressiong
为表达式内容,与pointcut-ref
属性一起使用环绕通知:
aop:around
- 使用接口
ProceddingJoinPoint
的proceed
方法明确调用切入点的方法 - 最灵活的一种通知,可以自定义什么时候执行切入点方法
- 使用接口
如下示例:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="accountService" class="com.oylong.service.impl.AccountServiceImpl"></bean>
<bean id="logger" class="com.oylong.utils.Logger"></bean>
<aop:config>
<aop:aspect id="logAdvice" ref="logger">
<aop:before method="printLog" pointcut="execution(public void com.oylong.service.impl.AccountServiceImpl.saveAccount())"></aop:before>
</aop:aspect>
</aop:config>
</beans>
之后即会在运行saveAccount
方法前,调用printLog
方法
切入点表达式:
execution(public void com.oylong.service.impl.AccountServiceImpl.saveAccount())
全通配写法:
* *..*.*(..)
一般不用这个,而是切到业务层实现类的所有方法,如
* com.oylong.service.impl.*.*(..)
- 访问修饰符可以省略:
execution(void com.oylong.service.impl.AccountServiceImpl.saveAccount())
- 返回值可以使用通配符,表示任意返回值:
execution(* com.oylong.service.impl.AccountServiceImpl.saveAccount())
- 包名可以使用通配符,标识任意包,有几级包就要使用几个
*.
:execution(* *.*.*.*.AccountServiceImpl.saveAccount())
- 包名可以使用
..
表示当前包及其子包:execution(* *..AccountServiceImpl.saveAccount())
- 类名和方法名都可以使用
*
来通配:execution(* *..AccountServiceImpl.*())
- 参数类型:基本类型直接写数据类型,引用类型为包名.类名
- 参数类型可以使用通配符
*
表示匹配任意类型但是必须有参数 - 参数类型可以使用通配符
..
表示有无参数均可匹配
基于注解
首先配置xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="com.oylong"></context:component-scan> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
之后使用注解配置AOP
package com.oylong.utils; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; @Component("logger") @Aspect public class Logger { @Before("pt()") public void printLog() { System.out.println("this is a logger"); } @Pointcut("execution(* com.oylong.service.impl.*.*(..))") private void pt(){} }
需要配置
bean
的,加上@Bean
注解即可- 在配置类上使用
@EnableAspectJAutoProxy
这个注解就可以实现不适xml文件的方式使用AOP
- 在配置类上使用