凯哥Java 2019-10-31
不同于OOP--面向对象编程,提供一系列继承、重写、封装技术,纵向的丰富编程功能。spring AOP为面向横向的切面编程,当工程中很多类都有共同的需求时,可以针对这些类,将共用的方法抽离出来,形成一个切面方法,将他织入到这些类中。每当执行这些类的时候,自动触发织入的切面方法,这样就不用在这些类中写重复的代码。
一 AOP的基本概念
(1)Aspect(切面):通常是一个类,里面可以定义切入点和通知
(2)JointPoint(连接点):程序执行过程中明确的点,一般是方法的调用
(3)Advice(通知):AOP在特定的切入点上执行的增强处理,有before,after,afterReturning,afterThrowing,around
(4)Pointcut(切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式
(5)AOP代理:AOP框架创建的对象,代理就是目标对象的加强。Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理,前者基于接口,后者基于子类
二 Spring AOP
Spring中的AOP代理还是离不开Spring的IOC容器,代理的生成,管理及其依赖关系都是由IOC容器负责,Spring默认使用JDK动态代理,在需要代理类而不是代理接口的时候,Spring会自动切换为使用CGLIB代理,不过现在的项目都是面向接口编程,所以JDK动态代理相对来说用的还是多一些。
AOP有两种实现方式,一种基于XML配置,一种基于注解,本篇先写一个基于XML配置的例子,下篇中讲解基于注解的AOP编程。

1、在spring中使用AOP变成,不止要导入spring-aop.jar,还需要导入spring-aspects.jar、aspectjweaver.jar和aopalliance.jar,但是aspectjweaver.jar被spring-aspects.jar依赖,aopalliance.jar被spring-aop.jar依赖,spring-aop.jar又被spring-mvc.jar依赖,所以只要导入spring-mvc.jar和spring-aspects.jar就行了。
pom.xml文件:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>4.0.5.RELEASE</spring.version>
</properties>
<dependencies>
<!-- springMvc框架,它依赖于spring的其他jar包,会自动导入spring的core、beans、web等jar包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>2、编写被增强的类,即被织入切面的类LittleBallImpl.java:
package springAop;
public class LittleBallImpl {
/*
* 需要aop代理的方法
* getLittleBallName()
*/
public void getLittleBallName(String name){
System.out.println("hello, I am little ball!");
}
}3、编写方法执行前、执行后、执行前后的增强类PrintDate.java、PrintWeather.java、AroundPoint.java,其中PrintDate通过在切入方法入参中添加JointPoint来获取被切方法的入参:
package springAop;
import java.util.Date;
import org.aspectj.lang.JoinPoint;
/**
* 切面类
* @author qiaozhong
*/
public class PrintDate {
/**
* 织入的具体业务方法,实现业务逻辑
* JointPoint可获得被切的方法的入参
*/
public void printDate(JoinPoint joinPoint){
//获取被切的方法的入参
Object[] o=joinPoint.getArgs();
System.out.println(String.valueOf(o[0]) + new Date());
}
}package springAop;
public class PrintWeather {
/**
* 织入的具体业务方法,实现业务逻辑
*/
public void printWeather(){
System.out.println("Today is sunny");
}
}package springAop;
import org.aspectj.lang.ProceedingJoinPoint;
public class AroundPoint {
/*
* 环绕通知
* */
public void aroundPrint(ProceedingJoinPoint point) throws Throwable {
System.out.println("环绕通知前。。。。。");
point.proceed();
System.out.println("环绕通知后。。。。。。");
}
}4、配置切面的配置文件spring-aop.xml,要加入aop相关的约束声明:
<?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"
xmlns:context="http://www.springframework.org/schema/context"
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-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- 配置bean -->
<bean id="littleBall" class="springAop.LittleBallImpl"></bean>
<!-- 配置切面的bean -->
<bean id="printDate" class="springAop.PrintDate"></bean>
<bean id="printWeather" class="springAop.PrintWeather"></bean>
<bean id="aroundPoint" class="springAop.AroundPoint"></bean>
<!-- 配置AOP -->
<aop:config>
<!-- 配置切面和通知 order:优先级,越小优先级越高-->
<aop:aspect id="date" ref="printDate" order="1">
<!-- 配置切面表达式 -->
<aop:pointcut id="addDate" expression="execution(* springAop.LittleBallImpl.get*(..))" />
<!-- 配置切面方法 -->
<aop:before method="printDate" pointcut-ref="addDate"/>
<aop:after method="printDate" pointcut-ref="addDate"/>
</aop:aspect>
<!-- 配置切面和通知 order:优先级,越小优先级越高-->
<aop:aspect id="weather" ref="printWeather" order="2">
<!-- 配置切面表达式 -->
<aop:pointcut id="addWeather" expression="execution(* springAop.LittleBallImpl.get*(..))" />
<!-- 配置切面方法 -->
<aop:before method="printWeather" pointcut-ref="addWeather"/>
<aop:after method="printWeather" pointcut-ref="addWeather"/>
</aop:aspect>
<!-- 配置切面和通知 order:优先级,越小优先级越高-->
<aop:aspect id="aroundP" ref="aroundPoint" order="3">
<!-- 配置切面表达式 -->
<aop:pointcut id="aPoint" expression="execution(* springAop.LittleBallImpl.get*(..))" />
<!-- 配置切面方法 -->
<aop:around method="aroundPrint" pointcut-ref="aPoint"/>
</aop:aspect>
</aop:config>
</beans>5、编写测试类TestAop.java:
package springAop;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestAop {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("springConfig/spring-aop.xml");
LittleBallImpl littleBallImpl = (LittleBallImpl)ac.getBean(LittleBallImpl.class);
littleBallImpl.getLittleBallName("hello ,I am little ball! Today is ");
}
}测试结果:
hello ,I am little ball! Today is Thu Oct 31 14:35:43 CST 2019 Today is sunny 环绕通知前。。。。。 hello, I am little ball! 环绕通知后。。。。。。 Today is sunny hello ,I am little ball! Today is Thu Oct 31 14:35:43 CST 2019
结果分析:
1、先执行了addDate切面方法,通过JointPoint获取了被切方法的入参“hello ,I am little ball! Today is”
2、执行了addWeather切面方法
3、执行AroundPoint切面前置方法
4、执行业务类LittleBallImpl
5、执行AroundPoint切面后置方法
6、执行了addWeather切面方法
7、执行了addDate切面方法,通过JointPoint获取了被切方法的入参“hello ,I am little ball! Today is”