Spring AOP可以实现对指定的类的公共方法进行拦截,添加前置和后置处理,甚至对方法调用进行mock替换。内部实现原理是使用的JAVA的动态代理(针对具有接口的类)或者CGLIB(针对没有接口的类)。
下面以一个具体的代码例子来演示Spring AOP的使用。
1. 新建一个idea的maven工程
pom.xml添加AOP需要的依赖包:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>5.1.3.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.9.1</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.1</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.1.3.RELEASE</version> </dependency>
2.Spring AOP的配置
在resources目录下新增applicationContext.xml文件,进行Spring AOP的配置。
<?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: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-4.3.xsd"> <bean id="userService" class="io.spring2go.corespring.command.aop.UserServiceImpl"></bean> <bean id="logAdvisor" class="io.spring2go.corespring.command.aop.LogAdvisor"></bean> <aop:config> <aop:aspect ref="logAdvisor"> <aop:pointcut expression="execution(* io.spring2go.corespring.command.aop.*.*(..))" id="pointUserService"/> <aop:before method="doBefore" pointcut-ref="pointUserService"/> <aop:after method="doAfter" pointcut-ref="pointUserService"/> <aop:around method="doAround" pointcut-ref="pointUserService"/> <aop:after-returning method="doReturn" pointcut-ref="pointUserService"/> <aop:after-throwing method="doThrowing" throwing="ex" pointcut-ref="pointUserService"/> </aop:aspect> </aop:config> </beans>
3.进行AOP处理的接口和实现类
接口:
package io.spring2go.corespring.command.aop; public interface UserService { public String fsindUserById(int id); }
实现类:
package io.spring2go.corespring.command.aop; public class UserServiceImpl implements UserService{ @Override public String fsindUserById(int id) { System.out.println("find user by id["+id+"]...."); if(id <= 0){ throw new IllegalArgumentException("user is not exist!"); } return "tom"; } }
4.AOP代理类
package io.spring2go.corespring.command.aop; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; public class LogAdvisor { /** * 在核心业务执行前执行,不能阻止核心业务的调用。 * @param joinPoint */ public void doBefore(JoinPoint joinPoint){ System.out.println("-----doBefore().invoke-----"); System.out.println(" 此处意在执行核心业务逻辑前,做一些安全性的判断等等"); System.out.println(" 可通过joinPoint来获取所需要的内容"); System.out.println("-----End of doBefore()------"); } /** * 手动控制调用核心业务逻辑,以及调用前和调用后的处理, * * 注意:当核心业务抛异常后,立即退出,转向After Advice * 执行完毕After Advice,再转到Throwing Advice * @param pjp * @return * @throws Throwable */ public Object doAround(ProceedingJoinPoint pjp) throws Throwable { System.out.println("-----doAround().invoke-----"); System.out.println(" 此处可以做类似于Before Advice的事情"); String targetName = pjp.getTarget().getClass().getName(); String methodName = pjp.getSignature().getName(); Object[] arguments = pjp.getArgs(); Class targetClass = Class.forName(targetName); Method[] method = targetClass.getMethods(); Map<String,Object> map = new HashMap<>(); for (Method m : method) { if (m.getName().equals(methodName)) { Class[] tmpCs = m.getParameterTypes(); } } //调用核心逻辑 Object retVal = pjp.proceed(); System.out.println(" 此处可以做类似于After Advice的事情"); System.out.println("-----End of doAround()------"); return retVal; } /** * 核心业务逻辑退出后(包括正常执行结束和异常退出),执行此Advice * @param joinPoint */ public void doAfter(JoinPoint joinPoint) { System.out.println("-----doAfter().invoke-----"); System.out.println(" 此处意在执行核心业务逻辑之后,做一些日志记录操作等等"); System.out.println(" 可通过joinPoint来获取所需要的内容"); System.out.println("-----End of doAfter()------"); } /** * 核心业务逻辑调用正常退出后,不管是否有返回值,正常退出后,均执行此Advice * @param joinPoint */ public void doReturn(JoinPoint joinPoint) { System.out.println("-----doReturn().invoke-----"); System.out.println(" 此处可以对返回值做进一步处理"); System.out.println(" 可通过joinPoint来获取所需要的内容"); System.out.println("-----End of doReturn()------"); } /** * 核心业务逻辑调用异常退出后,执行此Advice,处理错误信息 * @param joinPoint * @param ex */ public void doThrowing(JoinPoint joinPoint,Throwable ex) { System.out.println("-----doThrowing().invoke-----"); System.out.println(" 错误信息:"+ex.getMessage()); System.out.println(" 此处意在执行核心业务逻辑出错时,捕获异常,并可做一些日志记录操作等等"); System.out.println(" 可通过joinPoint来获取所需要的内容"); System.out.println("-----End of doThrowing()------"); } }
5. 客户端运行
package io.spring2go.corespring.command.aop; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestMain { public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); UserService userService = (UserService) ac.getBean("userService"); userService.fsindUserById(1); System.out.println("============="); try { userService.fsindUserById(0); } catch (Exception e) { System.out.println("异常捕获"); } } }