AOP的作用:在不修改源代码的情况下,可以实现功能增强
AOP思想:基于代理思想,对原来目标对象,创建代理对象,在不修改原对象代码的情况下,通过代理对象,调用增强功能的代码,从而对原有业务方法进行增强
AOP的应用场景:
(1)记录日志
(2)监控方法运行时间(监控性能)
(3)权限控制
(4)缓存优化(第一次调用查询数据库,将查询结果放入内寸对象,第二次调用,直接从内存对象返回,不需要查询数据库)
(5)事务管理(调用方法前开启事务,调用方法后关闭事务)
AOP实现原理:
JAK动态代理:点击打开链接
JDK动态代理只能对实现了接口的类产生代理
Cglib动态代理:可以对没有实现接口的类产生代理,实际上是生成了目标类的子类来增强。
Spring的AOP中相关术语的介绍:
Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点。
Pointcut(切入点):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义。
Advice(通知/增强):所谓通知是指拦截到Joinpoint之后所要做的事情就是通知。通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下,Introduction可以在运行期为动态的添加一些方法或Field。
Target(目标对象):代理的目标对象。
Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。spring采用动态代理织入,二Aspect采用编译期和类装载期织入。
Proxy(代理):一个类被AOP织入后增强,就产生一个结果代理类
Aspect(切面):是切入点和通知(引介)的结合。
1. Spring中AOP编程(xml方式)
Spring AOP开发需要IOC容器的支持,所以IOC所必须的六个jar包一定要导入;还需要导入AOP的jar包:
(1)AOP联盟的jar包:com.springsource.org.aopalliance-1.0.0.jar
(2)Spring提供的AOP的jar包:spring-aop-4.2.4.RELEASE.jar
(3)AspectJ的jar包:com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
(4)Spring整合AspectJ的jar包:spring-aspects-4.2.4.RELEASE.jar
配置 applicationContext.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:context="http://www.springframework.org/schema/context"
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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- AOP配置 -->
<aop:config>
<!-- 配置切入点:告诉spring框架哪些方法需要被增强 -->
<aop:pointcut expression="execution(* com.xyz.service.abc.xxx(..))" id="pointcut1"/>
<!-- 配置切面:告诉spring框架调用切面类中的哪个方法来增强 -->
<aop:aspect ref="myAspectXml">
<aop:before method="xxxx" pointcut-ref="pointcut1"/>
</aop:aspect>
</aop:config>
</beans>
2. 切入点表达式的语法
expression="execution(* com.xyz.service.AccountService.xxx(..))"
语法:[修饰符] 返回类型 包名.类名.方法名{形式参数}
常见写法:
(1)execution(pubic * *(..)) 所有的public方法
(2)execution(* set *(..)) 所有set开头的方法
(3)execution(* com.xyz.service.AccountService.*(..)) AccountService类中的所有方法
(4)execution(* com.xyz.service.*.*(..)) com.xyz.service包下所有的方法
(5)execution(* com.xyz.service.*.*(..)) com.xyz.service包及其子包下所有的方法
3. spring中AOP的通知类型
3.1 前置通知:表示目标方法执行之前增强
应用:权限控制(权限不足,抛出异常),记录方法调用信息日志
<!-- 配置切入点表达式:告诉spring框架哪些方法需要被增强 -->
<aop:pointcut expression="execution(* com.xyz.service.abc.xxx(..))" id="pointcut1"/>
<!-- 配置前置通知:告诉spring在目标方法执行之前增强 -->
<aop:before method="xxxx" pointcut-ref="pointcut1"/>
3.2 后置通知
特点:在目标方法运行后,返回值后执行增强代码逻辑。
<!-- 配置切入点表达式:告诉spring框架哪些方法需要被增强 -->
<aop:pointcut expression="execution(* com.xyz.service.abc.xxx(..))" id="pointcut2"/>
<!-- 配置后置通知 -->
<aop:after-returningmethod="xxxx" pointcut-ref="pointcut2" returning="xx"/>
指定returning属性的值为xx,通知方法的形参的名字要与returning的值一致
3.3 环绕通知
特点:目标执行前后,都进行增强(控制目标方法执行)
应用场景:日志,缓存,权限,性能监控,事务管理
增强代码的方法要求:
接受的参数:ProceedingJoinPoin(可执行的连接点)
返回值Object返回值
抛出Throwble异常
<!-- 配置切入点表达式:告诉spring框架哪些方法需要被增强 -->
<aop:pointcut expression="execution(* com.xyz.service.abc.xxx(..))" id="pointcut3"/>
<!-- 配置环绕通知 -->
<aop:around method = "xxxx" pointcut-ref = "pointcut3"/>
3.4 异常抛出通知
作用:目标代码出现异常,通知执行。记录异常日志,通知管理员(短信,右键)
应用场景:处理异常(一般不可预知),记录日志。
<!-- 配置切入点表达式:告诉spring框架哪些方法需要被增强 -->
<aop:pointcut expression="execution(* com.xyz.service.abc.xxx(..))" id="pointcut4"/>
<!-- 配置异常抛出通知 -->
<aop:after-throwing method = "xxxx" pointcut-ref = "pointcut4" throwing="xx"/>
需要给异常通知指定throwing属性,表示异常的名字,异常通知方法的形参名字要与此处一致.
3.5 最终通知
作用:不管目标方法是否发生异常,最终通知都会执行(类似finally代码功能)
应用场景:释放资源(关闭文件,关闭数据库连接,网络连接,释放内寸对象)
<!-- 配置切入点表达式:告诉spring框架哪些方法需要被增强 -->
<aop:pointcut expression="execution(* com.xyz.service.abc.xxx(..))" id="pointcut4"/>
<!-- 配置最终通知 -->
<aop:after method = "xxxx" pointcut-ref = "pointcut4" />
注意:最终通知和后置通知的区别:最终通知,不管异常与否,都执行;而后置通知在异常时不执行。
4. spring中AOP编程(注解方式)
配置applicationContext.xml
<!-- 开启spring注解扫描 -->
<context:component-scan base-package="xxx.xxx"></context:component-scan>
<!-- 开启aspectj自动代理 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
@Repository:
@Aspect:表示该类是一个切面类
@Before("execution(...)"):前置通知
@AfterReturning(value="execution(...)", returning="xxxx"):后置通知(通过value属性指定切入点表达式,returning属性指定返回值的名字,该方法形参的名字要与returning的值一致)
@Around("execution(...)"):环绕通知
@AfterThrowing(value = "execution(...)" ,throwing = "xx"):异常通知(通过value属性指定切入点表达式,throwing属性指定异常的名字。在该方法中增加一个形参,表示发生的异常,形参的名字与throwing属性的值一致)
@After("execution(...)"):最终通知
@Pointcut:用于低昂已切入点表达式的一个注解。可以把一些公用的切入点表达式用@Pointcut来表示。