AOP简介
AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
AOP核心概念
- 连接点(JoinPoint):程序执行过程中的任意位置,粒度为执行方法、抛出异常、设置变量等
- 切入点(Pointcut):匹配连接点的式子
- 在SpringAOP中,一个切入点可以描述一个具体方法,也可也匹配多个方法
- 匹配多个方法:所有的save方法,所有的get开头的方法,所有以Dao结尾的接口中的任意方法,所有带有一个参数的方法
- 通知(Advice):在切入点处执行的操作,也就是共性功能
- 切面(Aspect):描述通知与切入点的对应关系。
日志通知
前置通知
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" default-autowire="byType" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--目标对象--> <bean class="com.xiaoxu.aop.biz.impl.BookBizImpl" name="bookBiz"></bean> <!--通知--> <bean class="com.xiaoxu.aop.biz.advice.MyMethodBeforeAdvice" id="methodBeforeAdvice"></bean> <!--代理--> <bean class="org.springframework.aop.framework.ProxyFactoryBean" id="bookProxy"> <!-- 配置目标对象--> <property name="target" ref="bookBiz"></property> <!-- 配置代理的接口--> <property name="proxyInterfaces"> <list> <value>com.aop.biz.IBookBiz</value> </list> </property> <!--配置通知--> <property name="interceptorNames"> <list> <value>methodBeforeAdvice</value> </list> </property> </bean> </beans>
package com.xiaoxu.aop.biz.advice; import org.springframework.aop.MethodBeforeAdvice; import java.lang.reflect.Method; import java.util.Arrays; /** * @author小徐 * @site www.veryedu.cn * @company xu集团 * @create 2023-08-17 19:27 */ public class MyMethodBeforeAdvice implements MethodBeforeAdvice { @Override public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable { // 在这里,可以获取到目标类的全路径及方法及方法参数,然后就可以将他们写到日志表里去 String target = arg2.getClass().getName(); String methodName = arg0.getName(); String args = Arrays.toString(arg1); System.out.println("【前置通知:系统日志】:"+target+"."+methodName+"("+args+")被调用了"); } }
后置通知
package com.xiaoxu.aop.biz.advice; import org.springframework.aop.AfterReturningAdvice; import java.lang.reflect.Method; import java.util.Arrays; /** * @author小徐 * @site www.veryedu.cn * @company xu集团 * @create 2023-08-17 19:27 */ public class MyAfterReturningAdvice implements AfterReturningAdvice { @Override public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable { String target = arg3.getClass().getName(); String methodName = arg1.getName(); String args = Arrays.toString(arg2); System.out.println("【后置通知:买书返利】:"+target+"."+methodName+"("+args+")被调用了,"+"该方法被调用后的返回值为:"+arg0); } }
package com.xiaoxu.aop.advice; import java.util.Arrays; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; /** * @author小徐 * @site www.veryedu.cn * @company xu集团 * @create 2023-08-17 19:27 */ public class MyMethodInterceptor implements MethodInterceptor { @Override public Object invoke(MethodInvocation arg0) throws Throwable { String target = arg0.getThis().getClass().getName(); String methodName = arg0.getMethod().getName(); String args = Arrays.toString(arg0.getArguments()); System.out.println("【环绕通知调用前:】:"+target+"."+methodName+"("+args+")被调用了"); // arg0.proceed()就是目标对象的方法 Object proceed = arg0.proceed(); System.out.println("【环绕通知调用后:】:该方法被调用后的返回值为:"+proceed); return proceed; } }
异常通知
package com.xiaoxu.aop.biz.advice; import org.springframework.aop.ThrowsAdvice; import com.xiaoxu.aop.biz.Exception.PriceException; /** * @author小徐 * @site www.veryedu.cn * @company xu集团 * @create 2023-08-17 19:27 */ public class MyThrowsAdvice implements ThrowsAdvice { public void afterThrowing(PriceException ex) { System.out.println("【异常通知】:当价格发生异常,那么执行此处代码块!!!"); } }
过滤通知
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" default-autowire="byType" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--目标对象--> <bean class="com.xiaoxu.aop.biz.impl.BookBizImpl" name="bookBiz"></bean> <!--通知--> <bean class="com.xiaoxu.aop.biz.advice.MyMethodBeforeAdvice" id="methodBeforeAdvice"></bean> <bean class="com.xiaoxu.aop.biz.advice.MyAfterReturningAdvice" id="myAfterReturningAdvice"></bean> <bean class="com.xiaoxu.aop.biz.advice.MyMethodInterceptor" id="myMethodInterceptor"></bean> <bean class="com.xiaoxu.aop.biz.advice.MyThrowsAdvice" id="myThrowsAdvice"></bean> <bean class="org.springframework.aop.support.RegexpMethodPointcutAdvisor" id="regexpMethodPointcutAdvisor"> <property name="advice" ref="myAfterReturningAdvice"></property> <property name="pattern" value=".*buy"></property> </bean> <!--代理--> <bean class="org.springframework.aop.framework.ProxyFactoryBean" id="bookProxy"> <!-- 配置目标对象--> <property name="target" ref="bookBiz"></property> <!-- 配置代理的接口--> <property name="proxyInterfaces"> <list> <value>com.aop.biz.IBookBiz</value> </list> </property> <!--配置通知--> <property name="interceptorNames"> <list> <value>methodBeforeAdvice</value> <!-- <value>myAfterReturningAdvice</value>--> <value>regexpMethodPointcutAdvisor</value> <value>myMethodInterceptor</value> <value>myThrowsAdvice</value> </list> </property> </bean> </beans>