spring官网关于aop的介绍在以下两个章节:
https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#aop
https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#aop-api
1 aop基本概念
1.1 AOP是什么?
面向切面编程,Aspect Oriented Programming;
AOP是OOP的延续,将横切性问题从主业务逻辑中抽象出来;
什么是横切性问题?
业务代码中可以提炼出来的共通代码
降低了代码的耦合度,提高代码的复用性,提高了开发效率;
可以通过预编译方式和运行期动态代理实现程序功能
1.2 AOP与Spring Aop的关系
aop是一种思想
spring AOP 是AOP的一种实现
1.3 SpringAOP的应用
日志记录
事务管理
性能监控
权限验证
1.4 AOP相关术语
Aspect : 切面
通知+切点
Joint Point : 连接点
需要增强的方法,目标对象中的方法
PointCut : 切点
某一类型连接点的集合,切点表达式(下面详解)
Advice : 通知(下面详解)
增强的逻辑
通知执行的时机:前置通知,后置通知,异常通知,环绕通知,最终通知
Target Object : 目标对象
需要增强的对象
Proxy Object : 代理对象
增强后的对象
Weaving : 织入
将增强的逻辑按照通知的执行时机应用到切点生成代理对象的过程
2 spring中使用aop
2.1 Spring开启AOP支持的两种方式
XML
<aop:aspectj-autoproxy/>
Java Configuration : @EnableAspectJAutoProxy注解
@Configuration //声名配置类
@ComponentScan("com") //设置扫描包路径
@EnableAspectJAutoProxy //开启AOP支持
public class AppConfig {
}
2.2 Spring Aop代理方式
默认代理方式
优先使用gdk代理,不能使用gdk代理时,使用cglib代理
修改代理方式
使用xml开启AOP支持时,配置proxy-target-class属性
<aop:aspectj-autoproxy proxy-target-class="true"/>
使用Java Configuration开启AOP支持时,proxyTargetClass属性
@Configuration
@ComponentScan("com")
@EnableAspectJAutoProxy(proxyTargetClass = true) //使用cglib代理
public class AppConfig {
}
属性值为true时使用cglib代理,值为false时时默认的代理方式
2.3 Spring AOP切点表达式
表达式
execution:可以具体定义到某个方法以及方法的修饰符,返回值类型,参数个数以及类型
表达式规则
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?)
这里问号表示当前项可以有也可以没有,其中各项的语义如下
modifiers-pattern:方法的可见性,如public,protected;
ret-type-pattern:方法的返回值类型,如int,void等;
declaring-type-pattern:方法所在类的全路径名,如com.spring.Aspect;
name-pattern:方法名类型,如buisinessService();
param-pattern:方法的参数类型,如java.lang.String;
throws-pattern:方法抛出的异常类型,如java.lang.Exception;
execution(* com.dao..*.*(..))
within:只能具体定义到类
within(com.dao.impl.*)
this:指定目标对象类型
this(com.dao.impl.IndexDaoImpl)
target:指定代理对象类型
target(com.dao.impl.IndexDaoImpl)
args:定义方法参数得类型
args(java.lang.Integer,..)
也可以同时使用逻辑运算法同时使用多个不同的切点表达式
&& 、||、!
2.4 Spring AOP切点的实现
2.4.1 注解方式实现
@Component
@Aspect
public class MyAspectj {
//粒度小,精确控制到那个方法
@Pointcut("execution(* com.luban.dao..*.*(..))")
public void pointCutExecution() {
}
//粒度大,只能控制到那个类
@Pointcut("within(com.luban.dao.impl.*)")
public void pointCutWithin() {
}
//表示代理对象属于哪个类
@Pointcut("this(com.luban.dao.impl.IndexDaoImpl)")
public void pointCutThis() {
}
//表示目标对象属于哪个类
@Pointcut("target(com.luban.dao.impl.IndexDaoImpl)")
public void pointCutTarget() {
}
//按照目标对象的参数控制
@Pointcut("args(java.lang.Integer,..)")
public void pointCutArgs() {
}
//多个切点表达式配合使用
@Pointcut("pointCutTarget() && !pointCutArgs()")
public void pointCutManyExpression() {
}
}
2.4.2 XML方式实现
<aop:config>
<aop:pointcut id="myPonitCut" expression="execution(* com.dao..*.*(..))">
</aop:pointcut>
</aop:config>
2.5 Spring AOP 通知实现
2.5.1 注解方式实现
前置通知
@Before("pointCutManyExpression()")
public void before() {
System.out.println("before");
}
后置通知
@After("pointCutManyExpression()")
public void after() {
System.out.println("after");
}
最终通知
@AfterReturning("pointCutManyExpression()")
public void afterReturning() {
System.out.println("afterReturning");
}
//最终通知--按返回值类型匹配,并且获取返回值
@AfterReturning(
pointcut = "pointCutArgs()",
returning = "retVal")
public void doAccessCheck(Integer retVal) {
System.out.println("doAccessCheck");
System.out.println(retVal);
}
异常通知
//异常通知
@AfterThrowing("pointCutManyExpression()")
public void afterThrowing() {
System.out.println("afterThrowing");
}
//异常通知--获取抛出的异常
@AfterThrowing(
pointcut = "pointCutManyExpression()",
throwing = "ex")
public void doRecoveryActions(Exception ex) {
System.out.println("doRecoveryActions");
System.out.println(ex);
}
环绕通知
//环绕通知
@Around("pointCutManyExpression()")
public Object Around(ProceedingJoinPoint point) {
try {
System.out.println("Around-before");
Object result = point.proceed();
result = 12;
System.out.println("Around-after");
return result;
} catch (Throwable throwable) {
System.out.println("Around-throwing");
// throwable.printStackTrace();
} finally {
System.out.println("Around-returing");
}
return null;
}
XML方式实现
<aop:config>
<aop:aspect id="myAspect" ref="myXMLAspectj">
<aop:before method="before()" pointcut-ref="myPonitCut" ></aop:before>
</aop:aspect>
</aop:config>
2.6 Spring Introductions引入
作用 :
扩展一个类
2.6.1 注解方式
@Aspect
public class UsageTracking {
@DeclareParents(value="com.xzy.myapp.service.*+", defaultImpl=DefaultUsageTracked.class)
public static UsageTracked mixin;
}
2.6.2 XML方式
<aop:config>
<aop:aspect id="myAspect" ref="myXMLAspectj">
<aop:declare-parents types-matching="com.dao.impl.*+" implement-interface="com.dao.IndexDao" default-impl="com.dao.impl.IndexDaoImpl"></aop:declare-parents>
</aop:aspect>
</aop:config>
2.7 Spring Aspect Model
Spring切面模型,默认是单例的,可配置为原型的,配置@Aspectvalue值perthis(切点表达式)
@Aspect("perthis(com.xyz.myapp.SystemArchitecture.businessService())")
public class MyAspect {
}
注意:
配置切面模型是原型时,一定要配置切面类@Scope(“prototype”),否则会报错
xml只支持单例模型的,注解支持单例/原型的;