一.AOP概念
Paste_Image.png
Paste_Image.png
二.AOP术语
Paste_Image.png
三.Spring AOP框架AspectJ配置使用(基于注解的方式)
Paste_Image.png
(1)必要的jar包
Paste_Image.png
(2)在Spring bean的配置文件中加入aop命名空间;
(3)创建计算器接口(包含:增删改查方法)
package lxf.spring.aop.impl;
/**
* 计算器接口
* @author lxf
*/
public interface CalculatorInterface {
//加法
public int add(int i, int j);
//减法
public int sub(int i, int j);
//乘法
public int mul(int i, int j);
//除法
public int div(int i, int j);
}
(4)创建计算器的实现类
package lxf.spring.aop.impl;
import org.springframework.stereotype.Component;
/**
* 计算器接口实现类
* @author lxf
*/
@Component
public class CalculatorImpl implements CalculatorInterface {
@Override
public int add(int i, int j) {
return i+j;
}
@Override
public int sub(int i, int j) {
return i-j;
}
@Override
public int mul(int i, int j) {
return i*j;
}
@Override
public int div(int i, int j) {
// TODO Auto-generated method stub
return i/j;
}
}
(5)基于注解的方式配置AspectJ
在Spring配置文件中加入:
<!-- 扫描lxf.spring.aop.impl下带主键的bean,实例后加入IOC容器 -->
<context:component-scan base-package="lxf.spring.aop.impl"></context:component-scan>
<!-- 使AspectJ注解起作用,自动为匹配的类生成代理对象 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
(6)把横切关注点的代码抽象到切面的类LogAspect中;
package lxf.spring.aop.impl;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.List;
import javax.naming.spi.DirStateFactory.Result;
import org.aopalliance.intercept.Joinpoint;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* 切面类
* @author lxf
*/
//使用Order接口指定一个连接点处多个切面的优先级,值越小越优先执行
@Order(2)
//加入Aspect注解,证明是切面类,与配置文件中<aop:aspectj-autoproxy></aop:aspectj-autoproxy>配合
@Aspect
//切面首先是一个iOC容器的bean,使用Component注解的方式加入IOC容器
@Component
public class LogAspect {
/*
* 定义一个方法,用于声明切入点表达式,一般地,该方法中再不需要填入其他代码
* 使用 @Pointcut注解来声明切入点表达式
* 后面的其他通知直接使用方法名引用该切入点表达式
*/
@Pointcut("execution(public int lxf.spring.aop.impl.CalculatorInterface.*(..))")
public void declareJointPointExpression(){}
/*
* 前置通知:在lxf.spring.aop.impl.CalculatorInterface接口中的每个方法开始执行之前执行一段代码
* 声明该方法是一个前置通知,在执行目标方法前执行, *代表匹配所有方法,..代表匹配任意参数
*/
@Before("declareJointPointExpression()")
public void myBefore(JoinPoint joinPoint)
{
String methodName = joinPoint.getSignature().getName();
List<Object> args = Arrays.asList(joinPoint.getArgs());
System.out.println("The method begins methodName = " + methodName + ",参数=" + args);
}
/**
* 后置通知:在lxf.spring.aop.impl.CalculatorInterface接口中的每个方法开始执行之后执行一段代码
* 在目标方法执行之后(无论是否发生异常),执行的通知
* 在后置通知中不能访问目标方法执行的结果
*/
@After("declareJointPointExpression()")
public void myAfter(JoinPoint joinPoint)
{
String methodName = joinPoint.getSignature().getName();
System.out.println("The method end methodName = " + methodName);
}
/**
* 返回通知:在方法正常结束处执行的代码
* 是可以访问到方法的返回值的
*/
@AfterReturning(value="declareJointPointExpression()",returning="result")
public void myReturn(JoinPoint joinPoint,Object result)
{
String methodName = joinPoint.getSignature().getName();
System.out.println("The method return methodName = " + methodName + "返回值=" + result);
}
/**
* 异常通知:在目标方法出现异常时会执行的代码
* 可以访问到异常对象,并且可以指定在出现特定异常时在执行通知的代码
* @param joinPoint
* @param ex
*/
@AfterThrowing(value="declareJointPointExpression()",throwing="ex")
public void myThrow(JoinPoint joinPoint, Exception ex)
{
String methodName = joinPoint.getSignature().getName();
System.out.println("The method methodName = " + methodName + "出现了异常=" + ex);
}
/**
* 环绕通知需要携带ProceedingJoinPoint类型的参数
* 环绕通知类似于动态代理的全过程,ProceedingJoinPoint类型的参数可以决定是否执行目标方法
* @param pjd
@Around("execution(* lxf.spring.aop.impl.CalculatorInterface.*(..))")
public Object myArround(ProceedingJoinPoint pjd)
{
Object result = null;
String methodName = pjd.getSignature().getName();
List<Object> args = Arrays.asList(pjd.getArgs());
try {
//前置通知:
System.out.println("The method begins methodName = " + methodName + ",参数=" + args);
//执行目标方法
result = pjd.proceed(); //执行目标方法,相当于动态代理的method.invoke(target, args);
//返回通知
System.out.println("The method return methodName = " + methodName + "返回值=" + result);
} catch (Throwable e) {
//异常通知
System.out.println("The method methodName = " + methodName + "出现了异常=" + e);
//将异常继续抛出给运行时异常
throw new RuntimeException(e);
//e.printStackTrace();
}
//后置通知
System.out.println("The method end methodName = " + methodName);
return result;
} */
}
输出结果:
com.sun.proxy.$Proxy10
The method begins methodName = add,参数=[4, 2]
The method end methodName = add
The method return methodName = add返回值=6
6
The method begins methodName = div,参数=[4, 2]
The method end methodName = div
The method return methodName = div返回值=2
指定切面优先级
Paste_Image.png
四.Spring AOP基于配置文件的方式配置
(1)应用以上的接口和实现类和切面类,将注解去掉;
(2)Spring的配置文件applicationContext-xml.xml配置
<!-- 配置计算器实现类bean -->
<bean id="cal" class="lxf.spring.aop.xmlconfig.CalculatorImpl"></bean>
<!-- 配置日志切面bean -->
<bean id="logAspect" class="lxf.spring.aop.xmlconfig.LogAspect"></bean>
<!-- 配置验证切面bean -->
<bean id="validateAspect" class="lxf.spring.aop.xmlconfig.ValidateAspect"></bean>
<!-- 配置AOP -->
<aop:config>
<!-- 配置切点表达式 -->
<aop:pointcut expression="execution(public int lxf.spring.aop.xmlconfig.CalculatorInterface.*(..))" id="pointcut" />
<!-- 配置日志切面通知 -->
<aop:aspect ref="logAspect" order="2">
<!-- 前置通知 -->
<aop:before method="myBefore" pointcut-ref="pointcut"/>
<!-- 后置通知 -->
<aop:after method="myAfter" pointcut-ref="pointcut"/>
<!-- 返回通知 -->
<aop:after-returning method="myReturn" pointcut-ref="pointcut" returning="result"/>
<!-- 异常通知 -->
<aop:after-throwing method="myThrow" pointcut-ref="pointcut" throwing="ex"/>
</aop:aspect>
<!-- 配置验证切面通知 -->
<aop:aspect ref="validateAspect" order="1">
<aop:before method="myBefore" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
</beans>