JAVA框架 Spring AOP--切入点表达式和通知类型
一:AOP的相关术语:
1)Joinpoint(连接点):所谓的连接点是指那些可以被拦截点,在spring中这些点是指方法。因为在spring中支持方法类型的连接点。
2)Pointcut(切入点):所谓切入点是对那些连接点进行定义(增强。)也就是说拦截点包含切入点。
3)Advice(通知/增强):所谓通知就是拦截到joinpoint之后所要做的事情,就是通知。通知的类型分:前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)。
4)induction(引介):引介是一种特殊的通知在不修改类的代码前提下,introduction可以在运行期动态的添加一些方法或者field。
5)Target(目标对象): 代理的目标对象。
6)Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。
7)proxy(代理):一个类被AOP织入增强后,就产生结果代理类。
8)Aspect(切面):是切入点和通知的结合,需要我们自己编写和配置的。
二、AOP入门
我们使用的AOP是第三方的 aspectJ出的。所以需要整合他们的jar包。
1)引入jar包(需要导入4个jar包)。
需要如下jar包:
1、spring-aop-4.2.4.RELEASE.jar ----aop的原始jar包。
2、com.springsource.org.aopalliance-1.0.0.jar---aopalliance联盟的意思。aop联盟是针对aop制定的一些规范。如果想使用aop需要导入该jar包。
3、com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar依赖的aspectJ的jar包。
4、spring-aspects-4.2.4.RELEASE.jar spring本身的aspects支持的jar包。
2)约束引入
也之前的文件中:
引入:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" 5 http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 6 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- bean definitions here --> 7 8 </beans>
3)创建包结构:
接口:
1 package jd.com.demo; 2 3 public interface asTest { 4 void save(); 5 void update(); 6 }
实现类:
1 package jd.com.demo; 2 3 public class asTestImpl implements asTest { 4 @Override 5 public void save() { 6 System.out.println("this save method!"); 7 } 8 9 @Override 10 public void update() { 11 System.out.println("this is update!"); 12 } 13 }
切面类:
1 package jd.com.demo; 2 3 public class asdemo { 4 5 public void log(){ 6 System.out.println("日志输出"); 7 } 8 }
配置文件:
1)实现类声明:
1 <!--目标类的定义声明--> 2 <bean id="asTest" class="jd.com.demo.asTestImpl"/>
2)切面类声明:
1 <!--切面类的定义声明--> 2 <bean class="jd.com.demo.asdemo" id="asdemo"/>
引入切面和需要增强方法:
1 <aop:config > 2 <!--引入切面--> 3 <aop:aspect ref="asdemo"> 4 <!--定义通知类型--> 5 <aop:before method="log" pointcut="execution(public void jd.com.demo.asTestImpl.save())"/> 6 </aop:aspect> 7 </aop:config>
分析:
2-->aop;before 通知类型 前置通知,即被增强的方法在执行前执行增强方法。其中method和1对应即那个切面的那个方法。
1-->引入切面类。
3-->pointcut 切入点那个类的那个方法需要增强 后面跟的切入点表达式 。 修饰符 返回值 类的全路径 方法 用属性点连接。
3)切入点表达式:
1 <bean id="asTest" class="jd.com.demo.asTestImpl"/> 2 <bean class="jd.com.demo.asdemo" id="asdemo"/> 3 <aop:config > 4 <aop:aspect ref="asdemo"> 5 <!--1、execution()固定写法--> 6 <!--<aop:before method="log" pointcut="execution(public void jd.com.demo.asTestImpl.save())"/>--> 7 <!-- 8 2、修饰符public可以省略 9 <aop:before method="log" pointcut="execution( void jd.com.demo.asTestImpl.save())"/>--> 10 <!-- 11 3、返回值 可以写任意类型,比如:void 、String 会根据返回值得类型去匹配需要加强的类。 12 匹配任意类型* 该值不可以省略。 13 <aop:before method="log" pointcut="execution( * jd.com.demo.asTestImpl.save())"/>--> 14 <!-- 15 4、包路径可以省略,用*代替。但是只代表一层(*.asTestImpl 表示src下面的一层目录下面的实现类)。包的名字可以写成*Impl 表示以什么结尾 同样方法也可以这么写:*save 表示以save结尾的方法。 16 <aop:before method="log" pointcut="execution( * *.*.*.*Impl.*save())"/>--> 17 <!-- 18 4、方法的参数可以省略.. 表示任意参数。 19 <aop:before method="log" pointcut="execution( * *.*.*.*Impl.*save(..))"/>--> 20 </aop:aspect> 21 </aop:config>
注意:
再注入被加强的类的时候,设置字段的时候,类型需要写成接口的类型!!!!
4)通知类型:
1:前置通知 在方法运行前运行,可以对方法的参数来做校验。
1 <aop:before method="log" pointcut="execution( * *.*.*.*Impl.*save())"/>
2:最终通知类型通知,无论方法执行失败还是成功,都会在原先方法执行完之后执行。该类型可以用于一些资源的释放。、
1 <aop:after method="after" pointcut="execution( * *.*.*.*Impl.*save())"/>
3、后置通知 方法正常执行,才执行,一般用于方法成功执行的时候,对结果做一些简单的处理。
1 <aop:after-returning method="afterreturning" pointcut="execution( * *.*.*.*Impl.*save())"/>
4、异常通知:当被增强的方法,出现异常的时候,执行。
1 <aop:after-throwing method="afterthrowing" pointcut="execution( * *.*.*.*Impl.*save())"/>
5、环绕通知:在使用该通知的时候,如果不手动开启执行被增强方法的话。增强方法不会被执行。需要手动传入参数:ProceedingJoinPoint proceedingJoinPoint 然后执行: proceedingJoinPoint.proceed()。
1 <aop:around method="afteraround" pointcut="execution( * *.*.*.*Impl.*save())"/>
1 public void afteraround(ProceedingJoinPoint proceedingJoinPoint){ 2 System.out.println("环绕通知."); 3 try { 4 proceedingJoinPoint.proceed(); 5 } catch (Throwable throwable) { 6 throwable.printStackTrace(); 7 } 8 System.out.println("环绕通知."); 9 }
切面代码:
1 package jd.com.demo; 2 3 import org.aspectj.lang.ProceedingJoinPoint; 4 5 public class asdemo { 6 7 public void log(){ 8 System.out.println("日志输出"); 9 } 10 public void after(){ 11 System.out.println("最终类型通知!"); 12 } 13 public void afterreturning(){ 14 System.out.println("后置类型通知"); 15 } 16 public void afterthrowing(){ 17 System.out.println("后置异常通知."); 18 } 19 public void afteraround(ProceedingJoinPoint proceedingJoinPoint){ 20 System.out.println("环绕通知."); 21 try { 22 proceedingJoinPoint.proceed(); 23 } catch (Throwable throwable) { 24 throwable.printStackTrace(); 25 } 26 System.out.println("环绕通知."); 27 } 28 }