[原创]java WEB学习笔记108:Spring学习---基于配置文件的形式实现AOP

时间:2022-01-02 01:16:50

本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用

内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系。

本人互联网技术爱好者,互联网技术发烧友

微博:伊直都在0221

QQ:951226918

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

1.用基于 XML 的配置声明切面

  1) 除了使用 AspectJ 注解声明切面, Spring 也支持在 Bean 配置文件中声明切面. 这种声明是通过 aop schema 中的 XML 元素完成的.

  2) 正常情况下, 基于注解的声明要优先于基于 XML 的声明. 通过 AspectJ 注解, 切面可以与 AspectJ 兼容, 而基于 XML 的配置则是 Spring 专有的. 由于 AspectJ 得到越来越多的 AOP 框架支持, 所以以注解风格编写的切面将会有更多重用的机会.

   

  基于 XML ---- 声明切面

  3) 当使用 XML 声明切面时, 需要在 <beans> 根元素中导入 aop Schema

  4) 在 Bean 配置文件中, 所有的 Spring AOP 配置都必须定义在 <aop:config> 元素内部. 对于每个切面而言, 都要创建一个 <aop:aspect> 元素来为具体的切面实现引用后端 Bean 实例.

  5) 切面 Bean 必须有一个标示符, 供 <aop:aspect> 元素引用

  

  基于 XML ---- 声明切入点

  6) 切入点使用 <aop:pointcut> 元素声明

  7) 切入点必须定义在 <aop:aspect> 元素下, 或者直接定义在 <aop:config> 元素下:  定义在 <aop:aspect> 元素下: 只对当前切面有效 定义在 <aop:config> 元素下: 对所有切面都有效

  8)  基于 XML 的 AOP 配置不允许在切入点表达式中用名称引用其他切入点.

  

  基于 XML ---- 声明通知

  9) 在 aop Schema 中, 每种通知类型都对应一个特定的 XML 元素.

  10)通知元素需要使用 <pointcut-ref> 来引用切入点, 或用 <pointcut> 直接嵌入切入点表达式. method 属性指定切面类中通知方法的名称.

2.关于配置的核心代码

  aop-xml.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"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 配置bean -->
<bean id="arithmeticCaculator" class="com.jason.spring.aop.impl.ArithmeticCaculatorImpl"> </bean> <!-- 配置切面的bean -->
<bean id="loggingAspect" class="com.jason.spring.aop.impl.LoggingAspect"></bean>
<bean id="validateArgs" class="com.jason.spring.aop.impl.ValidateArgs"></bean> <!-- 配置aop -->
<aop:config>
<!-- 配置切点表达式 -->
<aop:pointcut expression="execution(* com.jason.spring.aop.impl.ArithmeticCaculator.*(..))" id="pointcut"/> <!-- 配置切面和通知 -->
<aop:aspect ref="loggingAspect" order="2">
<aop:before method="beforeMethod" pointcut-ref="pointcut"/>
</aop:aspect>
<aop:aspect ref="validateArgs" order="1">
<aop:before method="validateArgs" pointcut-ref="pointcut"/>
</aop:aspect> </aop:config> </beans>

  

3.其他代码

  

ArithmeticCaculator.java
 package com.jason.spring.aop.impl;

 public interface ArithmeticCaculator {

     int add(int i, int j);
int sub(int i, int j); int mul(int i, int j);
int div(int i, int j); }
ArithmeticCaculatorImpl.java
 package com.jason.spring.aop.impl;

 import org.springframework.stereotype.Component;

 //@Component

 public class ArithmeticCaculatorImpl implements ArithmeticCaculator {

     @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;
} }
LoggingAspect.java
 package com.jason.spring.aop.impl;

 import java.util.Arrays;
import java.util.List; 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.core.annotation.Order;
import org.springframework.stereotype.Component; /*@Order(1)
//把这个类声明为一个切面
//1.需要将该类放入到IOC 容器中
@Component
//2.再声明为一个切面
@Aspect*/
public class LoggingAspect { /**
*
* @Author:jason_zhangz@163.com
* @Title: declareJointPointExpression
* @Time:2016年12月6日
* @Description: 定义一个方法,用于声明切入点表达式。一般的,该方法不需要添加其他代码
*
*/
//@Pointcut("execution(* com.jason.spring.aop.impl.*.*(int, int))")
public void declareJointPointExpression(){} //声明该方法是一个前置通知:在目标方法开始之前执行 哪些类,哪些方法
//作用:@before 当调用目标方法,而目标方法与注解声明的方法相匹配的时候,aop框架会自动的为那个方法所在的类生成一个代理对象,在目标方法执行之前,执行注解的方法
//支持通配符
//@Before("execution(public int com.jason.spring.aop.impl.ArithmeticCaculatorImpl.*(int, int))")
//@Before("declareJointPointExpression()")
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);
} /**
*
* @Author:jason_zhangz@163.com
* @Title: afterMethod
* @Time:2016年12月1日
* @Description: 在方法执行后执行的代码,无论该方法是否出现异常
*
* @param joinPoint
*/
//@After("declareJointPointExpression()")
public void afterMethod(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
List<Object> args = Arrays.asList(joinPoint.getArgs());
System.out.println("The method " + methodName + " end " + args);
} /**
*
* @Author:jason_zhangz@163.com
* @Title: afterReturning
* @Time:2016年12月1日
* @Description: 在方法正常结束后执行代码,放回通知是可以访问到方法的返回值
*
* @param joinPoint
*/
//@AfterReturning( value="declareJointPointExpression()", returning="result")
public void afterReturning(JoinPoint joinPoint ,Object result){
String methodName = joinPoint.getSignature().getName();
System.out.println("The method " + methodName + " end with " + result);
} /**
*
* @Author:jason_zhangz@163.com
* @Title: afterThrowting
* @Time:2016年12月1日
* @Description: 在目标方法出现异常时会执行代码,可以访问到异常对象,且,可以指定出现特定异常时执行通知代码
*
* @param joinPoint
* @param ex
*/
//@AfterThrowing(value="declareJointPointExpression()",throwing="ex")
public void afterThrowting(JoinPoint joinPoint, Exception ex){
String methodName = joinPoint.getSignature().getName();
System.out.println("The method " + methodName + " occurs exceptions " + ex);
} /**
*
* @Author:jason_zhangz@163.com
* @Title: around
* @Time:2016年12月1日
* @Description: 环绕通知需要携带 ProceedingJoinPoint 类型的参数
* 环绕通知 类似于 动态代理的全过程
* ProceedingJoinPoint:可以决定是否执行目标方法
* 环绕通知必须有返回值,返回值即为目标方法的返回值
*
* @param proceedingJoinPoint
*/
//@Around("declareJointPointExpression()")
public Object around(ProceedingJoinPoint proceedingJoinPoint){ Object result = null;
String methodName = proceedingJoinPoint.getSignature().getName(); //执行目标方法
try {
//前置通知
System.out.println("The method " + methodName + "begin with" + Arrays.asList(proceedingJoinPoint.getArgs())); result = proceedingJoinPoint.proceed(); //后置通知
System.out.println("The method " + methodName + "end with" + result); } catch (Throwable e) {
//异常通知
System.out.println("The method occurs exception : " + e);
throw new RuntimeException();
}
//后置通知 System.out.println("The method " + methodName + "end with" + result); return result; } }
ValidateArgs.java
 package com.jason.spring.aop.impl;

 import java.util.Arrays;

 import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.context.annotation.Bean;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component; /**
*
* @ClassName:ValidateArgs
* @Description:可以使用@Order 注解指定切面的优先级,值越小优先级越高
* @author: jason_zhangz@163.com
* @date:2016年12月6日下午2:14:55
*
*/
/*@Order(2)
@Component
@Aspect*/
public class ValidateArgs { //@Before("execution(* com.jason.spring.aop.impl.ArithmeticCaculator.*(..))")
public void validateArgs(JoinPoint joinPoint){
System.out.println("validate:" + Arrays.asList(joinPoint.getArgs()));
} }
Main.java
 package com.jason.spring.aop.impl;

 import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main { public static void main(String[] args) { //1.创建Spring 的IOC 容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("aop-xml.xml"); //2.从IOC 容器中获取 bean实例
ArithmeticCaculator arithmeticCaculator = (ArithmeticCaculator) ctx.getBean(ArithmeticCaculator.class); //3.使用bean
int result = arithmeticCaculator.add(1, 2);
System.out.println(result); result = arithmeticCaculator.div(1, 2);
System.out.println(result); } }