spring的aop advice(可以理解为切面上的逻辑)用注解来实现有五种实现方式:
@Before(execution) 在方法执行前拦@AfterReturning(execution)在方法正常return结束后拦截 @AfterThrowing(execution) 在方法抛出异常时拦截@After(execution) 在方法结束后拦截,无论正常结束还是异常结束@Around(execution)唯一可以使用ProceedingJoinPoint参数来控制流程的advice,在方法执行前拦截,可以在切面逻辑中手动释放拦截,且可以在其后加入逻辑代码,该代码段会在方法执行后执行.这几种方式如果同时存在 , 会有一个先后顺序,下边测试后可以从打印结果中很明显地看到,但是一般情况下,尽量避免用这种先后顺序的方式来决定切面逻辑的设计,如果切面逻辑很复杂,可以用@Around整合在一起.
注意 : “表达式(execution)” 匹配到的方法必须为interface的实现类才可以,否则会抛出以下异常:Cannot proxy target class because CGLIB2 is not available. 如果一个类实现了接口 , spring就会通过jdk自带的Proxy 和 InvocationHandler自动生成代理 , 如果没有实现接口, 需要依赖cglib包 , 以直接操作二进制码的方式 , 来生成代理代码. 可以将获取到对象的class打印出来,可以很明显看到其中有”$$EnhancerByCGLIB”的字样,它是一个代理对象.
另外 , 测试中出现一个问题 , PointCut() 无法正常调用, 后来发现是aspectjrt 版本的问题 ,因为是跟着马士兵老师的视频走的 , 所以用的spring 2.5.6 的版本 , 我用pom构建项目的, spring2.5.6中集成的aspectjrt是1.6.1 版本的 , 这个版本和jdk1.7有冲突 , 将版本更换为新版的1.8.7就好了
下边上代码:
切面类:
@Aspect @Component public class LogInterceptor { //advice 切点语法规则,方法体不执行,其他advice可以直接将该方法作为参数 //按照该语法来执行拦截 @Pointcut("execution(* com.pindao.nine.dao.UserDao.show* (..))") public void pointCut1(){ System.out.println("this is pointCut"); } //拦截在方法执行之前 @Before("pointCut1()") public void before(){ System.out.println("method start..."); } //拦截在方法体执行之后,无论正常执行结束或异常结束 @After("execution(* com.pindao.nine.dao.UserDao.show* (..))") public void after(){ System.out.println("method end!"); } //拦截在方法正常return之后 @AfterReturning(value = "pointCut1()") public void afterReturn(){ System.out.println("this is afterReturing pointcut!"); } //拦截在方法抛出异常之后 @AfterThrowing("pointCut1()") public void afterThrowing(){ System.out.println("this is afterThrowing pointcut!"); } //拦截在方法体执行之前,插入代码,需要手动释放拦截,并且可以在继续运行之后插入代码 //ProceedingJoinPoint 参数只能在@Around下用,在其他advice下用,会抛出异常 @Around("pointCut1()") public Object around(ProceedingJoinPoint pjp) throws Throwable { System.out.println("this is around pointcut start..!"); //拦截结束,程序继续运行, 继续下一个拦截或者进行正常逻辑代码 Object obj = pjp.proceed(); System.out.println("this is around pointcut end..!"); return obj; } }执行切面的bean():
@Component("userDao") public class UserDaoImpl implements UserDao { public void showUser() { System.out.println("this is the real method start..."); // int i = 1/0; System.out.println("this is the real method end"); return 0; } }spring启用注解和切面配置 beans.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/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:annotation-config /> <context:component-scan base-package="com.pindao.nine" /> <!--aspectj是一个面向切面的框架,spring的aop,是基于aspectj来实现的--> <aop:aspectj-autoproxy /> </beans>手动启动spring容器,调用showUser()方法:
@Test public void testShowUserDao() throws Exception { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); UserDao userDao = (UserDao) context.getBean("userDao"); int result = userDao.showUser(); System.out.println(result); }执行结果: 1. 正常流程:
method start... this is around pointcut start..! this is the real method start... this is the real method end method end! this is afterReturing pointcut! this is around pointcut end..! 02.方法体抛出异常流程:
method start... this is around pointcut start..! this is the real method start... method end! this is afterThrowing pointcut! java.lang.ArithmeticException: / by zero ......下边是maven依赖:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>2.5.6</version> <exclusions> <exclusion> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> </exclusion> <exclusion> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>2.5.6</version> <exclusions> <exclusion> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> </exclusion> <exclusion> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.7</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.8.7</version> </dependency> <!-- cglib通过二进制的方式生成代理类 --> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.0</version> </dependency>