Spring AOP 三种实现方式
1.动态代理实现AOP基于XML的配置方式
业务逻辑接口
package com.chen.service;
public interface IOrderService {
String creatNewOrder(int orderMoney);
void payForOrder();
}
业务逻辑实现类
@Service("orderServiceBean")
public class OrderServiceImpl implements IOrderService {
@Override
public String creatNewOrder(int orderMoney) {
System.out.println("【业务层】创建新订单,订单金额为:"+orderMoney);
// Integer.parseInt("soso");
return UUID.randomUUID().toString();
}
@Override
public void payForOrder() {
System.out.println("【业务层】支付订单");
}
}
通知类
/**
* 日志通知
*/
public class LogAdvice implements MethodBeforeAdvice ,AfterReturningAdvice{
/**
* 前置通知(将会在目标对象的目标方法执行前调用)
* @param method 目标方法
* @param objects 参数列表
* @param target 目标对象
* @throws Throwable
*/
@Override
public void before(Method method, Object[] objects, Object target) throws Throwable {
System.out.println("目标对象:"+target);
System.out.println("目标方法:"+method.getName());
System.out.println("传入参数:"+ Arrays.toString(objects));
System.out.println("【日志】"+target+"的"+method.getName()+"方法于"+new Date()+"被执行");
}
/**
* 后置通知
* @param result
* @param method
* @param objects
* @param target
* @throws Throwable
*/
@Override
public void afterReturning(Object result, Method method, Object[] objects, Object target) throws Throwable {
System.out.println("返回值"+result);
System.out.println("目标对象:"+target);
System.out.println("目标方法:"+method.getName());
System.out.println("传入参数:"+ Arrays.toString(objects));
System.out.println("【日志】"+target+"的"+method.getName()+"方法于"+new Date()+"执行结束");
}
}
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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--被代理对象 -->
<bean id="orderServiceBean" class="com.chen.service.impl.OrderServiceImpl"/
<!--通知 -->
<bean id="logAdviceBean" class="com.chen.advice.LogAdvice"/>
<bean id="performanceAdviceBean" class="com.chen.advice.PerformanceAdvice"/>
<!--切入点:通过正则表达式描述指定切入点-->
<bean id="methodPointcutBean" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
<!--注入正则表达式:描述哪些方法为切入点-->
<property name="pattern" value=".*creat.*"/><!--以creat开头的方法-->
</bean>
<!--高级通知(Advisor) =通知(Advice)+切入点(Pointcut)-->
<bean id="performanceAdvisorBean" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<!-- 注入切入点-->
<property name="pointcut" ref="methodPointcutBean"/>
<!-- 注入通知-->
<property name="advice" ref="performanceAdviceBean"/>
</bean>
<!-- 自动代理创建 -->
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<!--Bean名称规则(数组)指定哪些bean创建代理 -->
<property name="beanNames">
<list>
<value>*ServiceBean</value>
</list>
</property>
<!--通知列表:需要执行哪些通知 -->
<property name="interceptorNames">
<list>
<value>logAdviceBean</value>
<value>performanceAdvisorBean</value>
</list>
</property>
</bean>
</beans>
2.使用Aspect实现切面,使用Spring AOP 进行配置
切面类
/**
* 使用AspectJ实现切面(普通POJO的实现方式)
*/
public class LogAspect {
/**
* 前置通知
* @param joinPoint
*/
public void beforeAdvice(JoinPoint joinPoint){
System.out.println("========【使用AspectJ实现前置通知】=========");
System.out.println("目标对象:"+joinPoint.getTarget());
System.out.println("目标方法:"+joinPoint.getSignature().getName());
System.out.println("参数列表:"+ Arrays.toString(joinPoint.getArgs()));
System.out.println("============================================");
}
/**
* 后置通知:方法正常执行后,有返回值,执行该后置通知;如果该方法执行出现异常,则不执行该后置通知
*/
public void afterReturningAdvice(JoinPoint joinpoint,Object returnVal){
System.out.println("==========【使用AspectJ实现后置通知】开始==================");
System.out.println("目标对象:" + joinpoint.getTarget());
System.out.println("目标方法:" + joinpoint.getSignature().getName());
System.out.println("参数列表:" + joinpoint.getArgs());
System.out.println("返回值:" + returnVal);
System.out.println("==========【使用AspectJ实现后置通知】结束==================");
}
/**
* 后置通知
*/
public void afterAdvice(JoinPoint joinpoint){
System.out.println("==========【使用AspectJ实现后置通知】开始==================");
System.out.println("目标对象:" + joinpoint.getTarget());
System.out.println("目标方法:" + joinpoint.getSignature().getName());
System.out.println("参数列表:" + joinpoint.getArgs());
System.out.println("==========【使用AspectJ实现后置通知】结束==================");
}
/**
* 异常通知:方法出现异常时,执行该通知
* @param joinpoint
* @param ex
*/
public void throwingAdvice(JoinPoint joinpoint,Exception ex){
System.out.println("==========【使用AspectJ实现异常通知】开始==================");
System.out.println("目标对象:" + joinpoint.getTarget());
System.out.println("目标方法:" + joinpoint.getSignature().getName());
System.out.println("出现异常:" + ex.getMessage());
System.out.println("==========【使用AspectJ实现异常通知】结束==================");
}
/**
* 环绕通知
*/
public Object aroundAdvice(ProceedingJoinPoint joinpoint) throws Throwable {
System.out.println("#########$环绕通知的前置部分$###############");
Object returnVal = joinpoint.proceed();
System.out.println("#########$环绕通知的后置部分$###############");
return returnVal;
}
}
XML配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--业务组件-->
<bean id="orderServiceBean" class="com.chen.service.impl.OrderServiceImpl"/>
<!-- 日志AspectJ切面-->
<bean id="logAspectBean" class="com.chen.advice.LogAspect"/>
<!--使用Aspect实现切面,使用Spring AOP 进行配置-->
<aop:config>
<!-- 配置切面-->
<!-- 注入切面bean-->
<aop:aspect ref="logAspectBean">
<!--定义Pointcut:通过expression表达式,来查找特定的方法(pointcut)-->
<aop:pointcut id="serviceMethodPointcut" expression="execution(* com.chen.service.impl.*.creat*(..))"/>
<!--配置前置通知 -->
<!--在pointcut切入点(serviceMethodPointcut)查找到的方法执行前,执行当前logAspectBean的beforeAdvice-->
<aop:before method="beforeAdvice" pointcut-ref="serviceMethodPointcut"/>
<!--配置后置通知-->
<!--returning属性:配置当前方法中用来接收返回值的参数名-->
<aop:after-returning returning="returnVal" method="afterReturningAdvice" pointcut-ref="serviceMethodPointcut"/>
<aop:after method="afterAdvice" pointcut-ref="serviceMethodPointcut"/>
<!--配置异常通知-->
<!--throwing属性:配置当前方法中用来接收当前异常的参数名-->
<aop:after-throwing throwing="ex" method="throwingAdvice" pointcut-ref="serviceMethodPointcut"/>
<!--配置环绕通知-->
<aop:around method="aroundAdvice" pointcut-ref="serviceMethodPointcut"/>
</aop:aspect>
</aop:config>
</beans>
3.使用AspectJ实现切面(注解的实现方式)
切面类
/**
* 使用AspectJ实现切面(注解的实现方式)
*/
//声明当前类为Aspect切面,并交给Spring容器管理
@Aspect
@Component
public class LogAnotationAspect {
private static final String POINTCUT_EXPRESSION = "execution(* com.chen.service.impl.*.creat*(..) )";
/**
* 前置通知
* @param joinPoint
*/
@Before(POINTCUT_EXPRESSION)
public void beforeAdvice(JoinPoint joinPoint){
System.out.println("========【使用AspectJ实现前置通知】=========");
System.out.println("目标对象:"+joinPoint.getTarget());
System.out.println("目标方法:"+joinPoint.getSignature().getName());
System.out.println("参数列表:"+ Arrays.toString(joinPoint.getArgs()));
System.out.println("============================================");
}
/**
* 后置通知:方法正常执行后,有返回值,执行该后置通知;如果该方法执行出现异常,则不执行该后置通知
*/
@AfterReturning(value=POINTCUT_EXPRESSION,returning = "returnVal")
public void afterReturningAdvice(JoinPoint joinpoint,Object returnVal){
System.out.println("==========【使用AspectJ实现后置通知】开始==================");
System.out.println("目标对象:" + joinpoint.getTarget());
System.out.println("目标方法:" + joinpoint.getSignature().getName());
System.out.println("参数列表:" + joinpoint.getArgs());
System.out.println("返回值:" + returnVal);
System.out.println("==========【使用AspectJ实现后置通知】结束==================");
}
/**
* 后置通知
*/
@After(POINTCUT_EXPRESSION)
public void afterAdvice(JoinPoint joinpoint){
System.out.println("==========【使用AspectJ实现后置通知】开始==================");
System.out.println("目标对象:" + joinpoint.getTarget());
System.out.println("目标方法:" + joinpoint.getSignature().getName());
System.out.println("参数列表:" + joinpoint.getArgs());
System.out.println("==========【使用AspectJ实现后置通知】结束==================");
}
/**
* 异常通知:方法出现异常时,执行该通知
* @param joinpoint
* @param ex
*/
@AfterThrowing(value = POINTCUT_EXPRESSION,throwing = "ex")
public void throwingAdvice(JoinPoint joinpoint,Exception ex){
System.out.println("==========【使用AspectJ实现异常通知】开始==================");
System.out.println("目标对象:" + joinpoint.getTarget());
System.out.println("目标方法:" + joinpoint.getSignature().getName());
System.out.println("出现异常:" + ex.getMessage());
System.out.println("==========【使用AspectJ实现异常通知】结束==================");
}
/**
* 环绕通知
*/
@Around(POINTCUT_EXPRESSION)
public Object aroundAdvice(ProceedingJoinPoint joinpoint) throws Throwable {
System.out.println("#########$环绕通知的前置部分$###############");
Object returnVal = joinpoint.proceed();
System.out.println("#########$环绕通知的后置部分$###############");
return returnVal;
}
}
XML配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--自动扫描器-->
<context:component-scan base-package="com.chen"/>
<!--配置AspectJ的自动代理-->
<aop:aspectj-autoproxy/>
</beans>