文章大纲
一、AOP介绍
二、Spring的AOP实战
三、AOP常用标签
四、项目源码及参考资料下载
五、参考文章
一、AOP介绍
1. 什么是AOP
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
简单的说它就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们的已有方法进行增强。
2. AOP的作用及优势
作用:在程序运行期间,不修改源码对已有方法进行增强。
优势:减少重复代码 提高开发效率 维护方便
3. AOP的实现方式
使用动态代理技术
二、Spring的AOP实战
1. 相关术语介绍
(1)Joinpoint(连接点):所谓连接点是指那些被拦截到的点,spring中,这些点是指方法,因为spring只支持方法类型的连接点
(2)PointCut(切入点):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义
(3)Advice(通知/增强):所谓通知是指拦截到Joinpoint之后所要做的事情就是通知,通知分为迁址通知、后置通知、异常通知、最终通知、环绕通知(切面要完成的功能)
前置通知:在方法之前执行
后置通知:在方法之后执行
异常通知:方法出现异常
最终通知:在后置之后执行
环绕通知:在方法之前和之后都执行
(4)Aspect(切面):是切入点和通知(引介)的结合,把增强应用到具体方法上面,过程就叫切面。也就是把增强用到切入点的过程
2. 实现方式
(1)基于aspectJ的xml配置
(2)基于aspectJ的注解方式
3. 基于aspectJ的xml配置代码实战
创建测试类Book.java
package aop;
public class Book {
public void add() {
System.out.println("add.......");
}
}
创建增强、通知类MyBook.java
package aop;
import org.aspectj.lang.ProceedingJoinPoint;
public class MyBook {
public void before1() {
System.out.println("前置增强...");
}
public void after1() {
System.out.println("后置增强...");
}
//环绕通知
public void around1(ProceedingJoinPoint proceedingJoinPoint) {
//方法之前
System.out.println("方法之前...");
//执行被增强方法
try {
proceedingJoinPoint.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
//方法之后
System.out.println("方法之后...");
}
}
src下配置文件bean.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/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 definitions here -->
<!-- 配置两个类的对象 -->
<bean id="book" class="aop.Book"></bean>
<bean id="myBook" class="aop.MyBook"></bean>
<!-- 配置aop操作 -->
<aop:config>
<!-- 配置切入点 expression就是写表达式的,id就是切入点名字 -->
<aop:pointcut expression="execution(* aop.Book.*(..))" id="pointcut1"/>
<!-- 配置切面 把增强用到方法上面 ref是增强类的对象 -->
<aop:aspect ref="myBook">
<!-- 配置前置增强 method表示增强类里面使用哪个方法作为前置 pointcut-ref表示把增强方法配置到哪个切入点-->
<aop:before method="before1" pointcut-ref="pointcut1"/>
<!-- 配置后置增强 -->
<aop:after method="after1" pointcut-ref="pointcut1"/>
<!-- 配置环绕增强 -->
<aop:around method="around1" pointcut-ref="pointcut1"/>
</aop:aspect>
</aop:config>
</beans>
测试代码如下
package aop;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestAop {
@Test
public void testUser() {
//加载spring配置文件,根据内容创建对象
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
Book book = (Book) context.getBean("book");
book.add();
}
}
运行结果如下
4. 基于aspectJ的注解方式代码实战
创建测试类Book.java
代码与xml配置中一样
创建增强、通知类MyBook.java
package aop2;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
//Spring就能发现用@Aspect注解的切面内并把它应用到目标对象上。
@Aspect
public class MyBook {
//在方法上面使用注解完成增强配置
@Before(value="execution(* aop2.Book.*(..))")
public void before1() {
System.out.println("前置增强...");
}
@After(value="execution(* aop2.Book.*(..))")
public void after1() {
System.out.println("后置增强...");
}
@Around(value="execution(* aop2.Book.*(..))")
//环绕通知
public void around1(ProceedingJoinPoint proceedingJoinPoint) {
//方法之前
System.out.println("方法之前...");
//执行被增强方法
try {
proceedingJoinPoint.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
//方法之后
System.out.println("方法之后...");
}
}
src下配置文件bean2.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/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 definitions here -->
<!-- 开启aop操作 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<!-- 创建对象 -->
<bean id="book" class="aop2.Book"></bean>
<bean id="myBook" class="aop2.MyBook"></bean>
</beans>
测试代码如下
package aop2;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestAop {
@Test
public void testUser() {
//加载spring配置文件,根据内容创建对象
ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
Book book = (Book) context.getBean("book");
book.add();
}
}
运行结果如下
三、AOP常用标签
(1)<aop:config>
用于声明开始aop的配置
(2)<aop:aspect>
作用:用于配置切面。
属性:
id:给切面提供一个唯一标识。
ref:引用配置好的通知类bean的id。
(3)<aop:pointcut>
作用:用于配置切入点表达式
属性:
expression:用于定义切入点表达式。
id:用于给切入点表达式提供一个唯一标识。
(4)<aop:before>
作用:用于配置前置通知
属性:
method:指定通知中方法的名称。
pointct:定义切入点表达式
pointcut-ref:指定切入点表达式的引用
(5)<aop:after-returning>
作用:用于配置后置通知
属性:
method:指定通知中方法的名称。
pointct:定义切入点表达式
pointcut-ref:指定切入点表达式的引用
(6)<aop:after-throwing>
作用:用于配置异常通知
属性:
method:指定通知中方法的名称。
pointct:定义切入点表达式
pointcut-ref:指定切入点表达式的引用
(7)<aop:after>
作用:用于配置最终通知
属性:
method:指定通知中方法的名称。
pointct:定义切入点表达式
pointcut-ref:指定切入点表达式的引用
(8)<aop:around>
作用:用于配置环绕通知
属性:
method:指定通知中方法的名称。
pointct:定义切入点表达式
pointcut-ref:指定切入点表达式的引用
四、项目源码及参考资料下载
链接:https://pan.baidu.com/s/1mU6ktTrwggh9SVmsoucJRg
提取码:jep8