初识SpringAOP
概述
AOP(Aspect Oriented Programming),即面向切面编程
通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延伸,是软件系统开发中的一个热点,也是Spring框架的一个重点.利用AOP可以实现业务逻辑各个部分的隔离,从而使得业务逻辑各个部分的耦合性降低,提高程序的可重用性,同时提高开发效率.
作用及优势
使用动态代理技术,在程序运行期间,不修改Java源代码对已有方法功能进行增强.
减少重复代码,提高开发效率.统一管理统一调用,方便维护
常用术语
Joinpoint(连接点)
在Spring中,连接点指的都是方法(要被增强功能的候选方法)
Pointcut(切入点)
在运行时已经被Spring的AOP实现了增强功能的方法
Advice(通知)
指的是拦截到Joinpoint之后要做的事情,即增强的功能
通知类型:前置通知 后置通知 异常通知 最终通知 环绕通知
Target(目标对象)
被代理的对象
Proxy(代理)
一个类被AOP织入增强后,即产生一个结果代理类
Weaving(织入)
指的是把增强用于目标对象,创建代理对象的过程
Aspect(切入)
指的是切入点和通知的结合
AOP配置
完全xml版
常规通知案例
/**
* 日志通知
*/
public class LogAdvice {
/**
* 前置通知
*/
public void beforeLog(){
System.out.println("【前置通知】记录用户操作日志");
}
/**
* 后置通知
*/
public void afterReturningLog(){
System.out.println("【后置通知】记录用户操作日志");
}
/**
* 异常通知
*/
public void afterThrowingLog(){
System.out.println("【异常通知】记录用户操作日志");
}
/**
* 最终通知
*/
public void afterLog(){
System.out.println("【最终通知】记录用户操作日志");
}
}
环绕通知案例
/**
* 环绕通知:
* 1.它是spring框架为我们提供了手动控制通知执行时间点和顺序的一种特殊通知类型
* 原理分析:
* 2.spring框架提供了ProceedingJoinPoint接口,作为环绕通知的参数。在环绕通知
* 执行的时候,spring框架会提供实例化对象,我们直接使用即可。该接口中提供了
* 两个方法:
* getArgs:获取参数列表
* proceed:相当于反射中的invoke方法
*
*/
public void aroundLog(ProceedingJoinPoint pjp){
// 前置通知
System.out.println("【环绕通知-前置通知】记录用户操作日志");
try {
// 获取参数列表
Object[] args = pjp.getArgs();
// 反射调用目标方法
Object retV = pjp.proceed(args);
// 后置通知
System.out.println("【环绕通知-后置通知】记录用户操作日志");
} catch (Throwable throwable) {
throwable.printStackTrace();
// 异常通知
System.out.println("【环绕通知-异常通知】记录用户操作日志");
}
// 最终通知
System.out.println("【环绕通知-最终通知】记录用户操作日志");
}
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
<!-- 导入AOP名称空间 -->
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--配置客户service-->
<bean id="customerService" class="com.XXX.service.impl.CustomerServiceImpl"></bean>
<!--配置日志通知-->
<bean id="logAdvice" class="com.XXX.advice.LogAdvice"></bean>
<!--配置aop:四个步骤-->
<!--第一步:通过aop:config声明aop的配置-->
<aop:config>
<!--第二步:通过aop:aspect配置切面,说明:
id:唯一标识名称
ref:指定通知bean对象的引用
-->
<aop:aspect id="logAspect" ref="logAdvice">
<!--第三步:通过aop:before配置前置通知,说明:
method:指定通知方法名称
pointcut-ref:指定切入点表达式
-->
<!--前置通知-->
<aop:before method="beforeLog" pointcut-ref="pt"/>
<!--后置通知-->
<aop:after-returning method="afterReturningLog" pointcut-ref="pt"/>
<!--异常通知-->
<aop:after-throwing method="afterThrowingLog" pointcut-ref="pt"/>
<!--最终通知-->
<aop:after method="afterLog" pointcut-ref="pt"/>
<!--环绕通知-->
<aop:around method="aroundLog" pointcut-ref="pt1"/>
<!--第四步:通过aop:pointcut配置切入点表达式,说明:
id:唯一标识名称
expression:指定切入点表达式
切入点表达式组成:
访问修饰符 返回值 包名称 类名称 方法名称 (参数列表)
-->
<aop:pointcut id="pt" expression="execution(public void com.XXX.service.impl.CustomerServiceImpl.saveCustomer())"/>
</aop:aspect>
</aop:config>
</beans>
切入点表达式
切入点表达式演化,说明:
全匹配方式:
public void com.XXX.service.impl.CustomerServiceImpl.saveCustomer()
访问修饰符可以省略:
void com.XXX.service.impl.CustomerServiceImpl.saveCustomer()
方法返回值可以使用通配符*:
* com.XXX.service.impl.CustomerServiceImpl.saveCustomer()
包名称可以使用通配符*(有多少级包,需要多少个*):
* *.*.*.*.CustomerServiceImpl.saveCustomer()
包名称可以使用..(表示当前包和子包):
* *..CustomerServiceImpl.saveCustomer()
类名称可以使用通配符*:
* *..*.saveCustomer()
方法名称可以使用通配符*:
* *..*.*()
参数列表可以使用通配符*(此时必须要有参数) :
* *..*.*(*)
参数列表可以使用..(有无参数均可):
* *..*.*(..)
实际项目中的表达式案例:
* com.XXX.service..*.*(..)
常用标签说明
<aop:config>
作用: 声明AOP配置
<aop:aspect>
作用: 配置切面
属性:
id: 唯一标识切面的名称
ref: 引用通知类bean的id
<aop:pointcut>
作用: 配置切入点表达式
属性:
id: 唯一标识切入点表达式名称
expression: 定义切入点表达式
<aop:before>
作用: 位置前置通知(在目标方法执行前执行)
属性:
method: 指定通知方法名称
pointcut: 定义切入点表达式
pointcut-ref: 引用切入点表达式的id
<aop:after-returning>
作用: 配置后置通知(在目标方法正常返回后执行.它和异常通知只能执行一个)
属性:
method: 指定通知方法名称
pointcut: 定义切入点表达式
pointcut-ref: 引用切入点表达式的id
<aop:after-throwing>
作用: 配置异常通知(在目标方法发送异常后执行,它和后置通知只能执行一个)
属性:
method: 指定通知方法名称
pointcut: 定义切入点表达式
pointcut-ref: 引用切入点表达式的id
<aop:after>
作用: 配置最终通知(无论目标方法是否正常返回,都会执行)
属性:
method: 指定通知方法名称
pointcut: 定义切入点表达式
pointcut-ref: 引用切入点表达式的id
<aop:around>
作用: 配置环绕通知(综和了前面四类通知,可以手动控制通知的执行时间点和顺序)
属性:
method: 指定通知方法名称
pointcut: 定义切入点表达式
pointcut-ref: 引用切入点表达式的id
xml和注解混合版
通知类
/**
* 日志通知类
* 注解说明:
* @Aspect:
* 作用:声明当前类是一个切面类,相当于xml中aop:aspect标签
* @Before:
* 作用:配置前置通知
* @AfterReturning:
* 作用:配置后置通知
* @AfterThrowing:
* 作用:配置异常通知
* @After:
* 作用:配置最终通知
* @Pointcut:
* 作用:配置切入点表达式
*/
@Component("logAdvice")
@Aspect
public class LogAdvice {
/**
* 切入点表达式
*/
@Pointcut("execution(* com.XXX.service..*.*(..))")
public void pt(){}
/**
* 前置通知
* @Before("execution(* com.XXX.service..*.*(..))")
*/
@Before("pt()")
public void beforeLog(){
System.out.println("【前置通知】记录用户操作日志");
}
/**
* 后置通知
*/
@AfterReturning("pt()")
public void afterReturningLog(){
System.out.println("【后置通知】记录用户操作日志");
}
/**
* 异常通知
*/
@AfterThrowing("pt()")
public void afterThrowingLog(){
System.out.println("【异常通知】记录用户操作日志");
}
/**
* 最终通知
*/
@After("pt()")
public void afterLog(){
System.out.println("【最终通知】记录用户操作日志");
}
/**
* 环绕通知:
* 1.它是spring框架为我们提供了手动控制通知执行时间点和顺序的一种特殊通知类型
* 原理分析:
* 2.spring框架提供了ProceedingJoinPoint接口,作为环绕通知的参数。在环绕通知
* 执行的时候,spring框架会提供实例化对象,我们直接使用即可。该接口中提供了
* 两个方法:
* getArgs:获取参数列表
* proceed:相当于反射中的invoke方法
*
*/
@Around("pt()")
public void aroundLog(ProceedingJoinPoint pjp){
// 前置通知
System.out.println("【环绕通知-前置通知】记录用户操作日志");
try {
// 获取参数列表
Object[] args = pjp.getArgs();
// 反射调用目标方法
Object retV = pjp.proceed(args);
// 后置通知
System.out.println("【环绕通知-后置通知】记录用户操作日志");
} catch (Throwable throwable) {
throwable.printStackTrace();
// 异常通知
System.out.println("【环绕通知-异常通知】记录用户操作日志");
}
// 最终通知
System.out.println("【环绕通知-最终通知】记录用户操作日志");
}
}
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"
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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--配置扫描包-->
<context:component-scan base-package="com.XXX"/>
<!--开启spring对注解aop的支持-->
<aop:aspectj-autoproxy/>
</beans>
完全注解版
配置类
/**
* spring配置类
*
* 注解说明:
* 1.@Configuration:声明当前类是spring配置类
* 2.@ComponentScan:配置扫描包,相当于xml中<context:component-scan/>标签
* 3.@EnableAspectJAutoProxy:启用spring对注解AOP的支持,
* 相当于xml中<aop:aspectj-autoproxy/>标签
*/
@Configuration
@ComponentScan(value = {"com.XXX"})
@EnableAspectJAutoProxy
public class SpringConfiguration {
}
初识SpringAOP的更多相关文章
- Android动画效果之初识Property Animation(属性动画)
前言: 前面两篇介绍了Android的Tween Animation(补间动画) Android动画效果之Tween Animation(补间动画).Frame Animation(逐帧动画)Andr ...
- 初识Hadoop
第一部分: 初识Hadoop 一. 谁说大象不能跳舞 业务数据越来越多,用关系型数据库来存储和处理数据越来越感觉吃力,一个查询或者一个导出,要执行很长 ...
- python学习笔记(基础四:模块初识、pyc和PyCodeObject是什么)
一.模块初识(一) 模块,也叫库.库有标准库第三方库. 注意事项:文件名不能和导入的模块名相同 1. sys模块 import sys print(sys.path) #打印环境变量 print(sy ...
- 初识IOS,Label控件的应用。
初识IOS,Label控件的应用. // // ViewController.m // Gua.test // // Created by 郭美男 on 16/5/31. // Copyright © ...
- UI篇(初识君面)
我们的APP要想吸引用户,就要把UI(脸蛋)搞漂亮一点.毕竟好的外貌是增进人际关系的第一步,我们程序员看到一个APP时,第一眼就是看这个软件的功能,不去关心界面是否漂亮,看到好的程序会说"我 ...
- Python导出Excel为Lua/Json/Xml实例教程(一):初识Python
Python导出Excel为Lua/Json/Xml实例教程(一):初识Python 相关链接: Python导出Excel为Lua/Json/Xml实例教程(一):初识Python Python导出 ...
- 初识SpringMvc
初识SpringMvc springMvc简介:SpringMVC也叫Spring Web mvc,属于表现层的框架.Spring MVC是Spring框架的一部分,是在Spring3.0后发布的 s ...
- 初识redis数据类型
初识redis数据类型 1.String(字符串) string是redis最基本的类型,一个key对应一个value. string类型是二进制安全的.意思是redis的string可以包含任何数据 ...
- Redis初识、设计思想与一些学习资源推荐
一.Redis简介 1.什么是Redis Redis 是一个开源的使用ANSI C 语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value 数据库,并提供多种语言的API.从2010 年 ...
随机推荐
- mysql连接报10038
1. netstat -ntpl # 查看端口状态,发现3306状态丢失(不理解操作,但确实解决了问题) 2. iptables -vnL # 这里要清除防火墙中链中的规则 3. iptable ...
- Codeforces 1295E Permutation Separation
题目链接 link Solution 暴力一眼就可以看出来,枚举分界点,然后左右两边统计答案即可,但复杂度是我们无法接受的 然后我们看我们可以优化哪一部分 \(1^0\) 枚举:这部分没有办法优化 \ ...
- 基于邻接表的长度为k的简单路径的求解
描述 一个连通图采用邻接表作为存储结构.设计一个算法,判断无向图中任意给定的两点是否存在一条长度为k的简单路径. 输入 多组数据,每组m+3数据行.第一行有两个数字n,m和k,代表有n个顶点,m条边和 ...
- 通过java语言实现MD5加密
通过java语言实现MD5加密public static String getMd5(String str) { try { MessageDigest md5 = MessageDigest.get ...
- hessian学习笔记
一.hessian是什么 Hessian是一个轻量级的remoting onhttp工具,使用简单的方法提供了RMI的功能. 相比WebService,Hessian更简单.快捷.采用的是二进制RPC ...
- jsp页面之间传中文参数显示乱码问题的解决
最近在项目中遇到jsp页面通过url传递参数,出现乱码,但是在本地是正常显示,在服务器上却是乱码,找了好久都没找到解决方法,最终在大神的帮助下解决了这个问题 比如从a.jsp像b.jsp页面传递参数 ...
- iOS简单音乐实现、React-Native完整项目、仿闲鱼京东列表分页、语音识别、网络加载过度动画等源码
iOS精选源码 iOS快速入手语音识别.听写.评测.播报 网络加载数据的过渡动画(仿简书网页) iOS 封装跑马灯和轮播效果 crash防护组件,适用常见常用的数组,字典等crash保护 iOS:高仿 ...
- phpcms添加图片投票
1phpcms加入投票选项的图片上传功能,从我的文件下载,然后到phpcms目录下直接覆盖即可. 当然这边出现了一个bug,修改投票选项不能修改的bug,只需要修改vote_option_class. ...
- F5 BIG-IP之一前期随笔(应用交付网络产品)
ADN:应用交付网络 TMOS: Traffic managment operation system (流量管理系统) 一个实时的全应用代理流量管理操作系统 PVA ...
- 吴裕雄--天生自然python学习笔记:抓取网络公开数据
当前,有许多政府或企事业单位会在网上为公众提供相关的公开数据.以 http://api.help.bj.cn/api/均 .cn/api /网站为例,打开这个链接,大家可以看到多种可供调用的数据 . ...