AspectJ的AOP实现:有两种方式,一种是基于XML配置文件,一种是基于注解的,由于注解更为常用,这里
这里只针对注解来学习。
--------------------------------------------------------------------------------------
1 package com.sjl.aspectj.annotation; 2 3 import org.aspectj.lang.JoinPoint; 4 import org.aspectj.lang.ProceedingJoinPoint; 5 import org.aspectj.lang.annotation.*; 6 import org.springframework.stereotype.Component; 7 8 /** 9 * 切面类,在此类中编写通知 10 * */ 11 @Aspect 12 @Component //这个注解的作用是实例化对象,相当于在配置文件中<bean id="" class="">
//由于是个java类,所以要实例化,相当于在Spring容器中声明这个文件是java类,
//并且是一个切面类 13 public class MyAspect { 14 //定义切入点表达式 15 @Pointcut("execution(* com.sjl.jdk.*.*(..))") 16 //用一个返回值为void、方法体为空的方法来命名切入点 17 private void myPoint(){ } 18 19 // 前置通知 20 @Before("myPoint()") 21 public void myBefore(JoinPoint joinPoint) { 22 System.out.print("前置通知 :模拟执行权限检查...,"); 23 System.out.print("目标类是:"+joinPoint.getTarget().getClass() ); 24 System.out.println(",被织入增强处理的目标方法为:" 25 +joinPoint.getSignature().getName()); 26 } 27 28 // 后置通知 29 @AfterReturning("myPoint()") 30 public void myAfterReturning(JoinPoint joinPoint) { 31 System.out.print("后置通知:模拟记录日志...," ); 32 System.out.println("被织入增强处理的目标方法为:" 33 + joinPoint.getSignature().getName()); 34 } 35 36 /** 37 * 环绕通知 38 * ProceedingJoinPoint 是JoinPoint子接口,表示可以执行目标方法 39 * 1.必须是Object类型的返回值 40 * 2.必须接收一个参数,类型为ProceedingJoinPoint 41 * 3.必须throws Throwable 42 */ 43 @Around("myPoint()") 44 public Object myAround(ProceedingJoinPoint proceedingJoinPoint) 45 throws Throwable { 46 // 开始 47 System.out.println("环绕开始:执行目标方法之前,模拟开启事务..."); 48 // 执行当前目标方法 49 Object obj = proceedingJoinPoint.proceed(); 50 // 结束 51 System.out.println("环绕结束:执行目标方法之后,模拟关闭事务..."); 52 return obj; 53 } 54 55 // 异常通知 56 @AfterThrowing(value = "myPoint()",throwing = "e") 57 public void myAfterThrowing(JoinPoint joinPoint, Throwable e) { 58 System.out.println("异常通知:" + "出错了" + e.getMessage()); 59 } 60 61 // 最终通知 62 @After("myPoint()") 63 public void myAfter() { 64 System.out.println("最终通知:模拟方法结束后的释放资源..."); 65 } 66 } 67 /** 68 * 提醒:同时记得jdk包下的目标类也要进行一个持久化层的一个注解的添加; 69 * */
#接口、目标类:
package com.sjl.jdk; public interface UserDao { void addUser(); void deleteUser(); }
package com.sjl.jdk; import org.springframework.stereotype.Repository; /** * UserDaoImpl是目标类,对其中的方法进行增强处理; */ @Repository("userDao") public class UserDaoImpl implements UserDao{ @Override public void addUser() { System.out.println("添加用户"); } @Override public void deleteUser() { System.out.println("删除用户"); } }
#配置文件的配置
<?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-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!--指定需要扫描的包,使注解生效--> <context:component-scan base-package="com.sjl"/> <!--启动注解声明式AspectJ支持--> <aop:aspectj-autoproxy /> </beans>
#测试类:
package com.sjl.aspectj.annotation; import com.sjl.jdk.UserDao; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; //测试类 public class TestAnnotationAspectj { public static void main(String[] args) { String xmlPath="applicationContext02Annotation.xml"; ApplicationContext ac=new ClassPathXmlApplicationContext(xmlPath);
//接口类型,向上造型 提高代码的复用性,其实也可以强转为父类,就强转为子类,
// 但是复用性就差,因为后面如果还有其它的代码就不利于使用
UserDao userDao=(UserDao)ac.getBean("userDao"); userDao.addUser();
}
}
运行结果:
环绕开始:执行目标方法之前,模拟开启事务... 前置通知 :模拟执行权限检查...,目标类是:class com.sjl.jdk.UserDaoImpl,被织入增强处理的目标方法为:addUser 添加用户 环绕结束:执行目标方法之后,模拟关闭事务... 最终通知:模拟方法结束后的释放资源... 后置通知:模拟记录日志...,被织入增强处理的目标方法为:addUser
说明:后置通知只有在目标方法成功执行之后才会被织入,而最终通知无论目标方法如何结束(包括异常中断)
都会被织入。