Spring框架-使用注解定义切面 AspectJ
AspectJ:面向切面的框架,他扩展了java语言,定义了AOP语法,能够在编译期提供代码的织入。
需求说明:使用注解实现日志切面。
定义切面:UserServiceLogger.java
1 package aop; 2 3 import java.util.Arrays; 4 5 import org.apache.log4j.Logger; 6 import org.aspectj.lang.JoinPoint; 7 import org.aspectj.lang.ProceedingJoinPoint; 8 import org.aspectj.lang.annotation.AfterReturning; 9 import org.aspectj.lang.annotation.Aspect; 10 import org.aspectj.lang.annotation.Before; 11 12 //日志处理类 增强处理类-日志 13 @Aspect 14 public class UserServiceLogger { 15 private Logger logger = Logger.getLogger(UserServiceLogger.class); 16 17 // 前置增强 表示的是service包下的UserService下面的任意方法 18 @Before("execution(* service.UserService.*(..))") 19 public void before(JoinPoint joinPoint) { 20 logger.info("调用" + joinPoint.getTarget() + "的" 21 + joinPoint.getSignature() + "方法,方法参数是:" 22 + Arrays.toString(joinPoint.getArgs())); 23 } 24 25 // 后置增强pointcut表示切入点表达式 returning表示返回值 26 @AfterReturning(pointcut="execution(* service.UserService.*(..))",returning="result") 27 public void afterReturning(JoinPoint joinPoint,Object result) { 28 logger.info("调用" + joinPoint.getTarget() + "的" 29 + joinPoint.getSignature() + "方法,方法的返回值是:" 30 +result); 31 } 32 33 // 异常抛出增强 34 public void afterThrowingError(JoinPoint joinPoint,RuntimeException e) { 35 logger.info("调用" + joinPoint.getTarget() + "的" 36 + joinPoint.getSignature().getName() + "方法,发生异常:" 37 +e); 38 } 39 //最终增强 40 public void after(JoinPoint joinPoint) { 41 logger.info("调用" + joinPoint.getTarget() + "的" 42 + joinPoint.getSignature().getName() + "方法,结束了" 43 ); 44 } 45 46 //环绕增强 47 public void aroundLogger(ProceedingJoinPoint joinPoint) { 48 //下面是目标方法的前面执行的处理 49 logger.info("调用" + joinPoint.getTarget() + "的" 50 + joinPoint.getSignature() + "方法,方法参数是:" 51 + Arrays.toString(joinPoint.getArgs())); 52 Object result;//这个相当于是目标方法 53 try { 54 //下面是目标方法之后进行的处理 55 result = joinPoint.proceed(); 56 logger.info("调用"+joinPoint.getTarget()+"的"+joinPoint.getSignature()+"方法,方法返回值:"+result); 57 58 } catch (Throwable e) { 59 logger.error(joinPoint.getSignature().getName()+"方法发生异常"+e); 60 e.printStackTrace(); 61 } finally{ 62 63 } 64 } 65 }
1 package dao.impl; 2 3 import org.springframework.stereotype.Repository; 4 5 import dao.UserDao; 6 import entity.User; 7 8 /** 9 * 用户DAO类,实现IDao接口,负责User类的持久化操作 10 */ 11 @Repository("userDao") 12 public class UserDaoImpl implements UserDao { 13 14 public void save(User user) { 15 // 这里并未实现完整的数据库操作,仅为说明问题 16 System.out.println("保存用户信息到数据库"); 17 //throw new RuntimeException("为了测试程序异常"); 18 } 19 }
1 package service.impl; 2 3 import javax.annotation.Resource; 4 5 import org.springframework.stereotype.Service; 6 7 import service.UserService; 8 import dao.UserDao; 9 import entity.User; 10 11 /** 12 * 用户业务类,实现对User功能的业务管理 13 */ 14 @Service("userService") 15 public class UserServiceImpl implements UserService { 16 17 // 声明接口类型的引用,和具体实现类解耦合 18 19 private UserDao dao; 20 21 22 public UserDao getDao() { 23 return dao; 24 } 25 26 @Resource//通过resource注解进行装配 27 public void setUserDao(UserDao dao) { 28 this.dao = dao; 29 } 30 31 32 33 public void addNewUser(User user) { 34 // 调用用户DAO的方法保存用户信息 35 dao.save(user); 36 System.out.println("注入进去的user对象的信息是:"+user.toString()); 37 } 38 }
核心配置文件:applicationContext.xml
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:context="http://www.springframework.org/schema/context" 5 xmlns:aop="http://www.springframework.org/schema/aop" 6 xsi:schemaLocation="http://www.springframework.org/schema/beans 7 http://www.springframework.org/schema/beans/spring-beans-3.2.xsd 8 http://www.springframework.org/schema/context 9 http://www.springframework.org/schema/context/spring-context-3.2.xsd 10 http://www.springframework.org/schema/aop 11 http://www.springframework.org/schema/aop/spring-aop-3.2.xsd"> 12 <!-- 扫描包中注解标注的类 --> 13 <context:component-scan base-package="service,dao" /> 14 <!--申明切面注解类 --> 15 <bean class="aop.UserServiceLogger"></bean> 16 <!--启动aspectj框架,让注解生效 --> 17 <aop:aspectj-autoproxy></aop:aspectj-autoproxy> 18 </beans>
编写测试方法:
1 package test; 2 3 import org.junit.Test; 4 import org.springframework.context.ApplicationContext; 5 import org.springframework.context.support.ClassPathXmlApplicationContext; 6 7 import service.UserService; 8 import service.impl.UserServiceImpl; 9 10 import entity.TestEntity; 11 import entity.User; 12 13 14 public class AopTest { 15 16 @Test 17 public void aopTest() { 18 ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); 19 UserService a = (UserService) ctx.getBean("userService"); 20 User user=new User(); 21 user.setUsername("丫丫"); 22 a.addNewUser(user); 23 } 24 25 }
运行结果:
12-31 11:32:53[INFO]aop.UserServiceLogger
-调用service.impl.UserServiceImpl@1283bb96的void service.UserService.addNewUser(User)方法,方法参数是:[entity.User@2a3b5b47]
保存用户信息到数据库
注入进去的user对象的信息是:entity.User@2a3b5b47
12-31 11:32:53[INFO]aop.UserServiceLogger
-调用service.impl.UserServiceImpl@1283bb96的void service.UserService.addNewUser(User)方法,方法的返回值是:null
有时候,一个切入点表达式会在很多的增强方法上面进行引用,一个一个的配置太麻烦了,我们可以统一定义一个切入点方法。
修改一下UserServiceLogger.java类
1 package aop; 2 3 import java.util.Arrays; 4 5 import org.apache.log4j.Logger; 6 import org.aspectj.lang.JoinPoint; 7 import org.aspectj.lang.ProceedingJoinPoint; 8 import org.aspectj.lang.annotation.AfterReturning; 9 import org.aspectj.lang.annotation.Aspect; 10 import org.aspectj.lang.annotation.Before; 11 import org.aspectj.lang.annotation.Pointcut; 12 13 //日志处理类 增强处理类-日志 14 @Aspect 15 public class UserServiceLogger { 16 private Logger logger = Logger.getLogger(UserServiceLogger.class); 17 //统一定义切入点 18 @Pointcut("execution(* service.UserService.*(..))") 19 public void pointcut(){ 20 21 } 22 // 前置增强 表示的是service包下的UserService下面的任意方法 23 @Before("pointcut()") 24 public void before(JoinPoint joinPoint) { 25 logger.info("调用" + joinPoint.getTarget() + "的" 26 + joinPoint.getSignature() + "方法,方法参数是:" 27 + Arrays.toString(joinPoint.getArgs())); 28 } 29 30 // 后置增强pointcut表示切入点表达式 returning表示返回值 31 @AfterReturning(pointcut="pointcut()",returning="result") 32 public void afterReturning(JoinPoint joinPoint,Object result) { 33 logger.info("调用" + joinPoint.getTarget() + "的" 34 + joinPoint.getSignature() + "方法,方法的返回值是:" 35 +result); 36 } 37 38 // 异常抛出增强 39 public void afterThrowingError(JoinPoint joinPoint,RuntimeException e) { 40 logger.info("调用" + joinPoint.getTarget() + "的" 41 + joinPoint.getSignature().getName() + "方法,发生异常:" 42 +e); 43 } 44 //最终增强 45 public void after(JoinPoint joinPoint) { 46 logger.info("调用" + joinPoint.getTarget() + "的" 47 + joinPoint.getSignature().getName() + "方法,结束了" 48 ); 49 } 50 51 //环绕增强 52 public void aroundLogger(ProceedingJoinPoint joinPoint) { 53 //下面是目标方法的前面执行的处理 54 logger.info("调用" + joinPoint.getTarget() + "的" 55 + joinPoint.getSignature() + "方法,方法参数是:" 56 + Arrays.toString(joinPoint.getArgs())); 57 Object result;//这个相当于是目标方法 58 try { 59 //下面是目标方法之后进行的处理 60 result = joinPoint.proceed(); 61 logger.info("调用"+joinPoint.getTarget()+"的"+joinPoint.getSignature()+"方法,方法返回值:"+result); 62 63 } catch (Throwable e) { 64 logger.error(joinPoint.getSignature().getName()+"方法发生异常"+e); 65 e.printStackTrace(); 66 } finally{ 67 68 } 69 } 70 }
同样是能够正确运行的。