Spring基础——AOP通知
spring(AOP通知)
切面
切面是封装通用业务逻辑的组件,可以作用到其他组件上。是spring组件中的某个方法、无返回类型、参数类型与通知类型有关。
一个切面 开启数据库 关闭数据库 开启事务 检查登录账号状态 监测账号权限
切点
用于指定哪些组件哪方法使用切面组件,Spring提供表达式来实现该制定。
通知
用于指定组件作用到目标组件的具体位置。
连接点(Joinpoint)
增强程序执行的某个特定位置(要在哪个地方做增强操作)。Spring仅支持方法的连接点,既仅能在方法调用前,方法调用后,方法抛出异常时等这些程序执行点进行织入增强。
切点(Pointcut)
切点是一组连接点的集合。AOP通过“切点”定位特定的连接点。通过数据库查询的概念来理解切点和连接点的关系再适合不过了:连接点相当于数据库中的记录,而切点相当于查询条件。
增强(Advice)
增强是织入到目标类连接点上的一段程序代码。表示要在连接点上做的操作。
切面(Aspect)
切面由切点和增强(引介)组成(可以包含多个切点和多个增强),它既包括了横切逻辑的定义,也包括了连接点的定义,SpringAOP就是负责实施切面的框架,它将切面所定义的横切逻辑织入到切面所指定的链接点中。
注解使用
@aspect 定义切面
@pointcut 定义切点
@before 标注Before Advice定义所在的方法
@afterreturning 标注After Returning Advice定义所在的方法
@afterthrowing 标注After Throwing Advice定义所在的方法
@after 标注 After(Finally) Advice定义所在的方法
@around 标注Around Advice定义所在的方法
1.AOP通知(配置xml文件)
QieMian1.java
public class QieMian1 { public void qianzhi(JoinPoint jp) { System.out.println("前置通知"); Object [] os = jp.getArgs(); for (Object object : os) { System.out.println("参数列表为:"+object); } } public void houzhi(Object a) { System.out.println("后置通知"+a); } public void yichang(JoinPoint jp,Throwable ta) { System.out.println("异常通知"); ta.printStackTrace(); } public void zuizhong() { System.out.println("最终通知"); } public void huanrao(ProceedingJoinPoint pjp) { try { System.out.println("环绕前"); pjp.proceed(); System.out.println("环绕后"); } catch (Throwable e) { // TODO Auto-generated catch block System.out.println("环绕异常"); e.printStackTrace(); }finally { System.out.println("环绕最终"); } } }
ApplicationContext.xml
<!-- 切面1 -->
<bean id="qieMian1" class="com.zy.spring.tools.aop.QieMian1"></bean> <!-- 创建一个切面的bean -->
<aop:config> <!-- aop配置标签 -->
<aop:pointcut expression="execution(* com.zy.spring.service.*.*(..))" id="pc1"/> <!-- 创建一个切点 -->
<aop:aspect order="1" ref="qieMian1"><!-- 创建一个切面 order是切面创建的顺序 ref链接上面创建的切面bean -->
<aop:before method="qianzhi" pointcut-ref="pc1"/><!-- 前置通知 -->
<aop:after-returning method="houzhi" pointcut-ref="pc1" returning="a"/> <!-- 后置通知 returning返回参数-->
<aop:after-throwing method="yichang" pointcut-ref="pc1" throwing="ta"/> <!-- 异常通知 throwing返回参数-->
<aop:after method="zuizhong" pointcut-ref="pc1"/> <!-- 最终通知 -->
<aop:around method="huanrao" pointcut-ref="pc1"/> <!-- 环绕通知 -->
</aop:aspect>
</aop:config>
常用的@AspectJ形式Pointcut表达式的标志符:
1、execution:
Spring AOP仅支持方法执行类型的Joinpoint 所以execution将会是我们用的最多的标志符,用它来帮我们匹配拥有指定方法前面的Joinpoint。
匹配方法execution
execution(返回类型 类的路径.类名.函数名(参数类型1,参数类型2))
execution(String com.chinasofti.Target.save(String))
execution(* com.chinasofti.Target.save(String))
execution(* com.chinasofti.*.save(String))
execution(* com.chinasofti.*.*(String))
execution(* com..*.*(..))
2、Within:
Within标志符只接受类型声明,它将匹配指定类型下所有的Joinpoint。
匹配类within
匹配到类
<aop:pointcut id="targetPintcut" expression="within(com.chinasofti.Target)"/>
调用这个类中的任何一个方法,都会走通知
匹配到包下的类
<aop:pointcut id="targetPintcut" expression="within(com.chinasofti.*)"/>
调用这个包下的任何一个类中的方法,都会走通知
匹配到包下及子包下的类
<aop:pointcut id="targetPintcut" expression="within(com..*)"/>
调用com这个包下的,所有子包及其一个类中的方法,都会走通知
2.AOP通知(注解配置)
QieMian2.java
@Aspect//定义切面 @Component//注册bean public class QieMian2 { @Pointcut("execution(* com.zy.spring.service.*.*(..))") //标记切点规则 public void pointcut() {};//创建一个空的方法,相当于切入方法 @Before("pointcut()") //前置通知 切点就是上面创建的pointcut()方法 public void qianzhi(JoinPoint jp) { System.out.println("注解前置通知"); Object [] os = jp.getArgs(); for (Object object : os) { System.out.println("参数列表为:"+object); } } @AfterReturning(pointcut="pointcut()",returning="a")//后置通知 returning是方法中定义的参数 public void houzhi(Object a) { System.out.println("注解后置通知"+a); } @AfterThrowing(pointcut="pointcut()",throwing="ta")//异常通知 throwing是方法中定义的参数 public void yichang(JoinPoint jp,Throwable ta) { System.out.println("注解异常通知"); ta.printStackTrace(); } @After("pointcut()")//最终通知 public void zuizhong() { System.out.println("注解最终通知"); } @Around("pointcut()")//环绕通知 public void huanrao(ProceedingJoinPoint pjp) { try { System.out.println("注解环绕前"); pjp.proceed();//放行 System.out.println("注解环绕后"); } catch (Throwable e) { // TODO Auto-generated catch block System.out.println("注解环绕异常"); e.printStackTrace(); }finally { System.out.println("注解环绕最终"); } } }
ApplicationContext.xml
<!-- 注解扫描AOP --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
使用注解aop功能,加入aop1的注解扫描即可。