目录
[1.2 AOP的优势](#1.2 AOP的优势)
[2.1 AOP相关的术语](#2.1 AOP相关的术语)
[2.2 AOP配置文件方式的入门](#2.2 AOP配置文件方式的入门)
[2.3 切入点的表达式](#2.3 切入点的表达式)
[2.4 AOP的通知类型](#2.4 AOP的通知类型)
1.SpringAOP概述
1.1SpringAOP的概念
什么是AOP的技术?
在软件业,AOP为AspectOrientedProgramming的缩写,意为:面向切面编程,AOP是一种编程范式,隶属于软工范畴,指导开发者如何组织程序结构
AOP最早由AOP联盟的组织提出的,制定了一套规范.Spring将AOP思想引入到框架中,必须遵守AOP联盟的规范
SpringAOP是通过预编译方式或者运行期动态代理实现程序功能的统一维护的一种技术
AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型
利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率
AOP:面向切面编程.(思想.---解决OOP遇到一些问题)
AOP 采取横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视、事务管理、安全检查、缓存)
为什么要学习AOP?可以在不修改源代码的前提下,对程序进行增强!!
1.2 AOP的优势
JDK 的动态代理技术
1、为接口创建代理类的字节码文件
2、使用ClassLoader 将字节码文件加载到JVM
3、创建代理类实例对象,执行对象的目标方法 cglib 代理技术
2.Spring的AOP技术-配置文件方式
2.1 AOP相关的术语
Joinpoint(连接点) 所谓连接点是指那些被拦截到的点。在spring中,这些点指的 是方法,因为spring只支持方法类型的连接点
Pointcut(切入点)-- 所谓切入点是指我们要对哪些Joinpoint进行拦截的定义
Advice(通知/增强)-- 所谓通知是指拦截到Joinpoint之后所要做的事情就是通知. 通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
Target(目标对象)-- 代理的目标对象
Weaving(织入)-- 是指把增强应用到目标对象来创建新的代理对象的过程
Proxy(代理)--一个类被AOP织入增强后,就产生一个结果代理类
Aspect(切面)--是切入点和通知的结合,以后咱们自己来编写和配置的
2.2 AOP配置文件方式的入门
1.导入依赖
XML
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.3</version>
</dependency>
</dependencies>
2.业务层模拟保存账户
java
package com.qcby.service.impl;
import com.qcby.service.UserService;
public class UserServiceImpl implements UserService {
@Override
public void save() {
System.out.println("业务层:保存用户.......");
}
}
package com.qcby.service;
public interface UserService {
void save();
}
3.配置切面类
java
package com.qcby.aspect;
public class MyXmlAspect {
/**
* 通知
* 自定义切面类=切入点(表达式)+通知(增强的代码)
*/
public void log(){
//发送手机短信
//发送邮件/记录日志/事务管理
System.out.println("增强的代码执行了......");
}
}
4.配置文件配置
配置文件:
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:context="http://www.springframework.org/schema/context"
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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
</beans>
(1)配置bean对象,把对象交给Spring管理
XML
<bean id="userService" class="com.qcby.service.impl.UserServiceImpl"/>
<!--定义切面类-->
<bean id="myXmlAspect" class="com.qcby.aspect.MyXmlAspect"/>
(2)切面类的配置
XML
<!--配置AOP的增强-->
<aop:config>
<aop:aspect ref="myXmlAspect">
<!--前置通知:在UserServiceImpl的save方法执行之前会增强-->
<aop:before method="log" pointcut="execution(public void com.qcby.service.impl.UserServiceImpl.save())"/>
</aop:aspect>
</aop:config>
5.编写测试代码
java
import com.qcby.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Demo {
@Autowired
private UserService userService;
/**
* 测试
*/
@Test
public void run1(){
userService.save();
}
}
测试:

2.3 切入点的表达式
在xml文件配置切入点的时候,需要定义表达式:
表达式格式如下:
execution([权限修饰符] 返回值类型 包名.类名.方法名(参数))
权限修饰符可以省略
返回值类型不能省略,要根据方法来编写返回值。可以用*代替
包名就是要增强的方法所在的包位置,拿
com.qcby.service.impl.UserServiceImpl.save()
举例:
com不能省略,可以用*代替
中间的包名可以用*省略,也可以使用..
类名也可以用*代替,例如*ServiceImpl
方法也可以用*代替
参数如果是一个参数可以用*代替,任意参数用..代替
把配置文件中的表达式换成这样也可以:
XML
<aop:before method="log" pointcut="execution(void *.qcby..*Impl.save(..))"/>
2.4 AOP的通知类型
1.前置通知
目标方法执行前,进行增强。
前置通知在入门中写过,不再赘述
2.最终通知
目标方法执行成功或者失败,进行增强。
配置:
XML
<!--最终通知:不论UserServiceImpl的save方法执行成功或者失败都会增强-->
<aop:after method="log" pointcut="execution(public void com.qcby.service.impl.UserServiceImpl.save())"/>
我们可以在save方法中模拟异常:
java
package com.qcby.service.impl;
import com.qcby.service.UserService;
public class UserServiceImpl implements UserService {
@Override
public void save() {
//模拟异常
int a=1/0;
System.out.println("业务层:保存用户.......");
}
}
测试方法不变,运行:

3.后置通知
目标方法执行成功后,进行增强。
配置:
XML
<!--后置通知:在save方法执行成功之后增强-->
<aop:after-returning method="log" pointcut="execution(public void com.qcby.service.impl.UserServiceImpl.save())"/>
测试:增强方法的执行在后面

4.异常通知
目标方法执行失败后,进行增强。
XML
<!-- 异常通知 在遇到异常时进行增强-->
<aop:after-throwing method="log" pointcut="execution(public void com.qcby.service.impl.UserServiceImpl.save())"/>
还是模拟异常:

把异常去掉:

5.环绕通知
目标方法执行前后,都可以进行增强。目标对象的方法需要手动执行。
配置环绕通知方法:
1.必须接收一个 ProceedingJoinPoint 参数(或 JoinPoint,但通常用 ProceedingJoinPoint,因为它可以控制目标方法的执行)。
2.必须调用 proceed() 方法来执行目标方法。
3.通常返回一个 Object 类型(如果目标方法有返回值的话,需要返回它)。
java
/**
* 环绕通知方法
*/
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕通知:目标方法执行前");
// 执行目标方法
Object result = joinPoint.proceed();
System.out.println("环绕通知:目标方法执行后");
return result;
}
配置:
XML
<!--环绕通知 在目标方法执行前后,都可以进行增强。目标对象的方法需要手动执行。-->
<aop:around method="logAround" pointcut="execution(public void com.qcby.service.impl.UserServiceImpl.save())"/>
执行:
