一 基于注解的方式配置Spring AOP
示例:
1.接口,及实现类
实现类使用@Component注解,配置到IOC容器中
public interface ArithmeticCalculator {
int add(int i, int j);
int sub(int i, int j);
int mul(int i, int j);
int div(int i, int j);
}
@Component("arithmeticCalculator")
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
@Override
public int add(int i, int j) {
int result = i + j;
return result;
}
@Override
public int sub(int i, int j) {
int result = i - j;
return result;
}
@Override
public int mul(int i, int j) {
int result = i * j;
return result;
}
@Override
public int div(int i, int j) {
int result = i / j;
return result;
}
}
2. 两个切面,验证切面 和 日志切面。验证切面在日志切面之前
(1)验证切面
//@Order 指定切面优先级,值越小切面优先级越高
@Order(1)
@Component
@Aspect
public class ValicationAspect {
//使用 LoggingAspect 中声明的切入点表达式
@Before(value = "com.spring.atguigu.aop.LoggingAspect.declareJoinPointExpression()")
public void validateArgs(JoinPoint joinPoint){
System.out.println("--> valicate:" +Arrays.asList(joinPoint.getArgs()));
}
}
(2)日志切面
//把这个类声明为一个切面:需把该类放到IOC容器中,再声明为一个切面
@Order(2)
@Component
@Aspect
public class LoggingAspect {
//定义一个方法,用于声明切入点表达式,一般地,该方法不需要添入其他代码
//使用@Pointcut 声明一个切入点表达式
//后面的其他通知直接使用方法名来引用当前切入点表达式
@Pointcut(value = "execution(public int com.spring.atguigu.aop.*.*(int,int))")
public void declareJoinPointExpression(){}
// 声明该方法为一个前置通知
@Before(value = "execution(public int com.spring.atguigu.aop.*.*(int,int))")
public void beforeMethod(JoinPoint joinpoint) {
// 获取方法名
String methodName = joinpoint.getSignature().getName();
// 获取参数
List<Object> args = Arrays.asList(joinpoint.getArgs());
System.out.println("the method " + methodName + " begins..." + args);
}
// 后置通知:在目标方法执行后(无论是否发生异常),执行的通知
// 在后置通知中,还不能访问目标方法的执行结果
@After(value = "execution(public int com.spring.atguigu.aop.*.*(int,int))")
public void afterMethod(JoinPoint joinpoint) {
// 获取方法名
String methodName = joinpoint.getSignature().getName();
System.out.println("the method " + methodName + " ends ...");
}
// 返回通知 在方法正常结束执行的代码
// 可以访问到结果
@AfterReturning(value = "declareJoinPointExpression()", returning = "result")
public void afterReturningMethod(JoinPoint joinpoint, Object result) {
String methodName = joinpoint.getSignature().getName();
System.out.println("the method " + methodName + " ends with " + result);
}
// 异常通知 方法发生异常时执行
// 可以访问到异常对象,且可以指定特定异常类型时,执行通知代码 public void afterThrowingMethod(JoinPoint
// joinpoint , NullPointerException e)
@AfterThrowing(value = "execution(public int com.spring.atguigu.aop.*.*(int,int))", throwing = "e")
public void afterThrowingMethod(JoinPoint joinpoint, Exception e) {
String methodName = joinpoint.getSignature().getName();
System.out.println("the method " + methodName + " occurs exception "
+ e);
}
/**
* 环绕通知需携带 ProceedingJoinPoint 类型的参数 环绕通知类似于动态代理的全过程,ProceedingJoinPoint
* 类型的参数可以决定是否执行目标方法 环绕通知必须有返回值,返回值即为目标方法的返回值
*
* @param pjd
* @return
*/
/*@Around(value = "execution(public int com.spring.atguigu.aop.*.*(int,int))")
public Object aroundMethod(ProceedingJoinPoint pjd) {
System.out.println("aroundMethod");
Object result = null;
String methodName = pjd.getSignature().getName();
try {
// 前置通知
System.out.println("the method" + methodName + " begins with"
+ Arrays.asList(pjd.getArgs()));
// 执行目标方法
result = pjd.proceed();
// 返回通知
System.out.println("the method " + methodName + " ends with "
+ result);
} catch (Throwable e) {
// 异常通知
System.out.println("the method " + methodName
+ " occurs exception " + e);
}
//后置通知
System.out.println("the method " + methodName + " ends ...");
return result;
}*/
}
注解说明:
@Component 将切面配置到IOC容器中@Aspect 声明为切面
@Order 指定切面优先级,值越小切面优先级越高
@Pointcut 声明一个切入点表达式
@Before声明该方法为一个前置通知
@After 后置通知 在目标方法执行后(无论是否发生异常),执行的通知
@AfterReturning 返回通知 在方法正常结束执行的代码
@AfterThrowing 异常通知 方法发生异常时执行
@Around 环绕通知需携带 ProceedingJoinPoint 类型的参数 环绕通知类似于动态代理的全过程,ProceedingJoinPoint
3.applicationContext.xml 配置文件
<context:component-scan base-package="com.spring.atguigu.aop"></context:component-scan>
<!-- 使AspectJ注解起作用:自动为匹配的类生成代理对象 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
4.测试类
public class Main {
public static void main(String[] args) {
ApplicationContext ctx= new ClassPathXmlApplicationContext("applicationContext.xml");
ArithmeticCalculator arithmeticCalculator = (ArithmeticCalculator) ctx.getBean("arithmeticCalculator");
int result = arithmeticCalculator.add(3, 3);
System.out.println("result:"+result);
result = arithmeticCalculator.div(12,6);
System.out.println(result);
}
}
5.结果:
--> valicate:[3, 3]
aroundMethod
the methodadd begins with[3, 3]
the method add ends with 6
the method add ends ...
result:6
--> valicate:[12, 6]
aroundMethod
the methoddiv begins with[12, 6]
the method div ends with 2
the method div ends ...
2
aroundMethod
the methodadd begins with[3, 3]
the method add ends with 6
the method add ends ...
result:6
--> valicate:[12, 6]
aroundMethod
the methoddiv begins with[12, 6]
the method div ends with 2
the method div ends ...
2
二、基于配置文件方式配置AOP
示例:
1.接口,实现类(和前面一样,只是去掉了注解)
public interface ArithmeticCalculator {
int add(int i, int j);
int sub(int i, int j);
int mul(int i, int j);
int div(int i, int j);
}
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
@Override
public int add(int i, int j) {
int result = i + j;
return result;
}
@Override
public int sub(int i, int j) {
int result = i - j;
return result;
}
@Override
public int mul(int i, int j) {
int result = i * j;
return result;
}
@Override
public int div(int i, int j) {
int result = i / j;
return result;
}
}
2. 验证切面,日志切面 (和前面一样,只是去掉注解)
public class ValicationAspect {
public void validateArgs(JoinPoint joinPoint){
System.out.println("--> valicate:" +Arrays.asList(joinPoint.getArgs()));
}
}
public class LoggingAspect {
public void beforeMethod(JoinPoint joinpoint) {
// 获取方法名
String methodName = joinpoint.getSignature().getName();
// 获取参数
List<Object> args = Arrays.asList(joinpoint.getArgs());
System.out.println("the method " + methodName + " begins..." + args);
}
public void afterMethod(JoinPoint joinpoint) {
// 获取方法名
String methodName = joinpoint.getSignature().getName();
System.out.println("the method " + methodName + " ends ...");
}
public void afterReturningMethod(JoinPoint joinpoint, Object result) {
String methodName = joinpoint.getSignature().getName();
System.out.println("the method " + methodName + " ends with " + result);
}
public void afterThrowingMethod(JoinPoint joinpoint, Exception e) {
String methodName = joinpoint.getSignature().getName();
System.out.println("the method " + methodName + " occurs exception "
+ e);
}
public Object aroundMethod(ProceedingJoinPoint pjd) {
System.out.println("aroundMethod");
Object result = null;
String methodName = pjd.getSignature().getName();
try {
// 前置通知
System.out.println("the method" + methodName + " begins with"
+ Arrays.asList(pjd.getArgs()));
// 执行目标方法
result = pjd.proceed();
// 返回通知
System.out.println("the method " + methodName + " ends with "
+ result);
} catch (Throwable e) {
// 异常通知
System.out.println("the method " + methodName
+ " occurs exception " + e);
}
//后置通知
System.out.println("the method " + methodName + " ends ...");
return result;
}
}
3.配置文件 applicationContext-xml.xml
<!-- 配置bean -->
<bean id = "arithmeticCalculator" class="com.spring.atguigu.aop.xml.ArithmeticCalculatorImpl"></bean>
<!-- 配置一个切面的bean -->
<bean id ="valicationAspect" class = "com.spring.atguigu.aop.xml.ValicationAspect" ></bean>
<bean id = "loggingAspect" class = "com.spring.atguigu.aop.xml.LoggingAspect"></bean>
<aop:config>
<!-- 配置切点表达式 -->
<aop:pointcut expression="execution(* com.spring.atguigu.aop.xml.ArithmeticCalculator.*(int , int ))"
id="pointcut"/>
<!-- 配置切面及通知 -->
<aop:aspect ref="loggingAspect" order="2">
<aop:before method="beforeMethod" pointcut-ref="pointcut"/>
<aop:after method="afterMethod" pointcut-ref="pointcut"/>
<aop:after-returning method="afterReturningMethod" pointcut-ref="pointcut" returning="result"/>
<aop:after-throwing method="afterThrowingMethod" pointcut-ref="pointcut" throwing="e"/>
<!-- 环绕通知 -->
<!-- <aop:around method="aroundMethod" pointcut-ref="pointcut"/> -->
</aop:aspect>
<aop:aspect ref="valicationAspect" order="1">
<aop:before method="validateArgs" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
4. 测试方法
public class Main {
public static void main(String[] args) {
ApplicationContext ctx= new ClassPathXmlApplicationContext("applicationContext-xml.xml");
ArithmeticCalculator arithmeticCalculator = (ArithmeticCalculator) ctx.getBean("arithmeticCalculator");
int result = arithmeticCalculator.add(3, 3);
System.out.println("result:"+result);
result = arithmeticCalculator.div(12,6);
System.out.println(result);
}
}
5.结果:
--> valicate:[3, 3]
the method add begins...[3, 3]
the method add ends ...
the method add ends with 6
result:6
--> valicate:[12, 6]
the method div begins...[12, 6]
the method div ends ...
the method div ends with 2
2