本篇博客知识点
学习SpringAOP第三种技术—利用注解完成拦截
AOP技术的本质为一个公式
切面 = 切点 + 通知
四种技术都只是通过不同形式完成这个公式而言,第三种是通过注解
第一步:写一个类 就是我们的切面
类名任意但是类前面必须加一个注解 @Aspect
底层Spring可以通过这个注解知道这个类就是我们的切面。
第二步:写切点 :字符内容为 切点语言 AspectJ
切点有两种形式写法,第一种是通过类成员变量
第二种形式:写在一个成员方法上,
第三步:写通知,通知有多种
通过注解写到成员方法名字上,方法内的 就是切面执行函数。
两种对应前面两个切点的使用方法
下面是对几种常用的拦截方法介绍
@Before :原型对象执行前拦截,
@After:原型对象执行后拦截
@Around: 可以原型对象执行前后拦截
@AfterReturning:原型对象执行时正常返回结果未出错时候 触发
@AfterThrowing:原型对象执行时未正常返回结果出错时候 触发
下面是两个切面的代码
package cn.hncu2.v3;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
//切面= 切点 + 通知
//@Aspect = @Pointcut + (@Before | @After | Around | @AfterReturning | @AfterThrowing 等当中至少有1种)
@Aspect
public class MyAdvisor {
@Pointcut(value="execution( * cn..Cat.*(..) )") //@Pointcut中的value属性来指定切点的表达式----用aspectj切点语言
public void aa(){ //该方法没别的功能,就是为了让@Pointcut有个寄居的地方,同时也用于标识该注解
}
@Pointcut(value="execution( * cn..Person.*(..) ) ")
public void bb(){
}
@Before(value="aa()") //由@Before通知的value属性指定PointCut(本例为aa()方法上的切点)
public void bf(){
System.out.println("前面拦拦......");
}
@After(value="aa()")
public void after1(){
System.out.println("后面拦拦1.....");
}
//下面的方法可以采用空参,但通过手动注入一个JoinPoint类型的参数,可以获得拦截"连接点"的信息如: 是否为方法执行、被拦截方法的名字、方法的对象等
@After(value="bb()")
public void after2(JoinPoint jp){//通过手动注入 jp参数 ---缺点:依赖JoinPoint类,因此如果没必要的话,就不加这个参数
System.out.println("后面拦拦2.....:"+ jp.getKind()+","+jp.getSignature().getName()+","+jp.getTarget() );
}
@Around(value="aa()") //Around通知的拦截方法必须依赖一个ProceedingJoinPoint参数,否则无法放行, 同时方法要返回Object(被放行方法的返回值)
public Object around(ProceedingJoinPoint p) throws Throwable{ //ProceedingJoinPoint 是 JoinPoint 的子类
System.out.println("前前前拦拦.....:"+ p.getKind()+","+p.getSignature().getName()+","+p.getTarget() );
Object res = p.proceed(); //放行
System.out.println("后后后拦拦....");
return res;
}
@AfterReturning(value="aa()")
public void afterReturn(){ //该方法可以注入JoinPoint参数,也可以不注入
System.out.println("方法正常返回之后......");
}
@AfterThrowing(value="aa()")
public void afterThrow(){ //该方法可以注入JoinPoint参数,也可以不注入
System.out.println("方法抛出异常之后.....");
}
}
package cn.hncu2.v3;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
//切面= 切点 + 通知
//@Aspect = @Pointcut + (@Before | @After | Around | @AfterReturning | @AfterThrowing 等当中至少有1种)
@Aspect
public class MyAdvisor2 {
//用表达式字符串来代替切点
private final String CUT="execution( * cn..Person.*(..) )";
@Before(CUT)
public void bf(){
System.out.println("前面拦拦......");
}
@Around(CUT)
public Object around(ProceedingJoinPoint p) throws Throwable{ //ProceedingJoinPoint 是 JoinPoint 的子类
System.out.println("前前前2拦拦.....:"+ p.getKind()+","+p.getSignature().getName()+","+p.getTarget() );
Object res = p.proceed(); //放行
System.out.println("后后后2拦拦....");
return res;
}
}
vvv.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
">
<!-- 自动代理 , 低版Spring可以用该自动代理类 替代 下面的自动代理标签
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean>
-->
<!-- 自动代理的标签 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<!-- 基于注解的切面 -->
<!-- <bean class="cn.hncu.v3.MyAdvisor"></bean> -->
<bean class="cn.hncu.v3.MyAdvisor2"></bean>
<bean id="p" class="cn.hncu.v3.Person"></bean>
<bean id="cat" class="cn.hncu.v3.Cat"></bean>
</beans>
package cn.hncu.v3;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Client {
@Test
public void t1(){
ApplicationContext ctx = new ClassPathXmlApplicationContext("cn/hncu/v3/vvv.xml");
Person p = ctx.getBean("p",Person.class);
p.run();
p.fun("lalala");
p.ok("hncu", 66);
Cat c = ctx.getBean("cat", Cat.class);
c.run();
}
}
执行结果