Spring AOP面向切面编程详解
前言
AOP即面向切面编程,是一种编程思想,OOP的延续。在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等等。在阅读本文前希望您已经对Spring有一定的了解
注:在能对代码进行添加注解方式实现AOP的话,并不推荐使用XML方式。换言之在XML方式配置更适用于不能对代码添加注解的情况下(注解配置方式推荐值>XML配置方式推荐值)
AOP相关术语
1.通知(Advice):在切面的某个特定的连接点上执行的动作,即当程序到达一个执行点后会执行相对应的一段代码,也称为增强处理。通知共有如下5种类型[前置通知 后置通知 返回通知 环绕通知 抛出异常后通知] 2.连接点(JoinPoint):程序执行的某个特定位置,例如类初始化前,类初始化后,方法执行前,方法执行后,方法抛出异常时等,Spring只支持方法级别的连接点,即方法执行前,方法执行后,方法抛出异常时 3.切入点(Pointcut):切入点是一个筛选连接点的过程,因为在你的工程中可能有很多连接点,你只是想让其中几个,在调用这几个方法之前、之后或者抛出异常时干点什么,那么就用切入点来定义这几个方法,让切点来筛选连接点,选中那几个你想要的方法 4.切面(Aspect):切面通常是指一个类,是通知和切入点的结合。到这里会发现连接点就是为了让你好理解切点产生的。通俗来说切面的配置可以理解为:什么时候在什么地方做什么事。切入点说明了在哪里干(指定到方法),通知说明了什么时候干什么 5.引入(Introduction):引入允许我们向现有的类添加新方法或属性 6.织入(Weaving):把切面应用到目标对象来创建新的代理对象的过程,织入一般发生在如下几个时机:
(1)编译时:当一个类文件被编译时进行织入,这需要特殊的编译器才可以做的到,例如AspectJ的织入编译器
(2)类加载时:使用特殊的ClassLoader在目标类被加载到程序之前增强类的字节代码
(3)运行时:切面在运行的某个时刻被织入,SpringAOP就是以这种方式织入切面的,原理应该是使用了JDK的动态代理技术
基于XML方式配置AOP
正常通知
1.编写业务类
public class HelloWorldBusiness {
public String sayHelloWorld(String language) {
String result = "Hello World " + language;
System.out.println("真正的业务方法执行啦~~~");
return result;
}
}
2.编写切面类
public class HelloWorldBusinessAspect {
public void beforeSayHelloWorld(String language) {
System.out.println("执行方法前运行,参数为:" + language);
}
public void afterSayHelloWorld(String language) {
System.out.println("执行方法后运行,参数为:" + language);
}
public void afterReturningSayHelloWorld(String language, String result) {
System.out.println("执行方法返回后运行,参数为:" + language + " 方法返回值为:" + result);
}
public void afterThrowingHelloWorld(String language, Throwable e) {
System.out.println("执行方法抛出异常后运行,参数为:" + language + "异常为:" + e);
}
}
3.编写配置文件
<?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-4.3.xsd"> <!-- 配置业务Bean -->
<bean id="helloWorldBusiness" class="roberto.growth.process.aop.HelloWorldBusiness" /> <!-- 配置切面Bean -->
<bean id="helloWorldBusinessAspect" class="roberto.growth.process.aop.HelloWorldBusinessAspect" /> <!-- 配置一个切面 -->
<aop:config>
<aop:aspect id="helloWorldAspect" ref="helloWorldBusinessAspect">
<!-- 配置一个切点 -->
<aop:pointcut id="sayHelloWorldPoint" expression="execution(public * roberto.growth.process.aop.HelloWorldBusiness.sayHelloWorld(..)) and args(language)" />
<!-- 配置前置通知 -->
<aop:before pointcut-ref="sayHelloWorldPoint" method="beforeSayHelloWorld" arg-names="language"/>
<!-- 配置前置通知 -->
<aop:after pointcut-ref="sayHelloWorldPoint" method="afterSayHelloWorld" arg-names="language"/>
<!-- 配置后置返回通知 -->
<aop:after-returning pointcut-ref="sayHelloWorldPoint" method="afterReturningSayHelloWorld" arg-names="language,result" returning="result" />
<!-- 异常通知 -->
<aop:after-throwing pointcut-ref="sayHelloWorldPoint" method="afterThrowingHelloWorld" arg-names="language,e" throwing="e" />
</aop:aspect>
</aop:config>
</beans>
4.运行HelloWorldBusiness的sayHelloWorld方法输出结果为
执行方法前运行,参数为:JAVA
真正的业务方法执行啦~~~
执行方法后运行,参数为:JAVA
执行方法返回后运行,参数为:JAVA 方法返回值为:Hello World JAVA
环绕通知
1.编写业务类
public class HelloWorldBusiness {
public String sayHelloWorld(String language) {
String result = "Hello World " + language;
System.out.println("真正的业务方法执行啦~~~");
return result;
}
}
2.编写切面类
public class HelloWorldBusinessAspect {
public void aroundSayHelloWorld(ProceedingJoinPoint joinPoint) {
String language = (String) joinPoint.getArgs()[0];
try {
System.out.println("执行方法前运行,参数为:" + language);
String result = (String) joinPoint.proceed();
System.out.println("执行方法后运行,参数为:" + language + " 方法返回值为:" + result);
} catch (Throwable e) {
System.out.println("执行方法抛出异常后运行,参数为:" + language + "异常为:" + e);
}
}
}
3.编写配置文件
<?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-4.3.xsd"> <!-- 配置业务Bean -->
<bean id="helloWorldBusiness" class="roberto.growth.process.aop.HelloWorldBusiness" /> <!-- 配置切面Bean -->
<bean id="helloWorldBusinessAspect" class="roberto.growth.process.aop.HelloWorldBusinessAspect" /> <!-- 配置一个切面 -->
<aop:config>
<aop:aspect id="helloWorldAspect" ref="helloWorldBusinessAspect">
<!-- 配置一个切点 -->
<aop:pointcut id="sayHelloWorldPoint" expression="execution(public * roberto.growth.process.aop.HelloWorldBusiness.sayHelloWorld(..))" />
<!-- 配置环绕通知 -->
<aop:around pointcut-ref="sayHelloWorldPoint" method="aroundSayHelloWorld" />
</aop:aspect>
</aop:config>
</beans>
4.运行HelloWorldBusiness的sayHelloWorld方法输出结果为
执行方法前运行,参数为:JAVA
真正的业务方法执行啦~~~
执行方法后运行,参数为:JAVA 方法返回值为:Hello World JAVA
使用MethodInterceptor实现AOP
1.编写业务类
public class HelloWorldBusiness {
public String sayHelloWorld(String language) {
String result = "Hello World " + language;
System.out.println("真正的业务方法执行啦~~~");
return result;
}
}
2.编写拦截器类 实现MethodInterceptor方法
public class HelloWorldBusinessAspect implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
// 获取被增强对象参数列表
String language = (String) invocation.getArguments()[0];
// 获取被增强对象的方法
Method method = invocation.getMethod();
// 继续执行业务方法
System.out.println("执行" + method.getName() + "方法前运行,参数为: " + language);
Object result = invocation.proceed();
System.out.println("执行方法返回后运行,参数为:" + language + " 方法返回值为:" + result);
return result;
}
}
3.编写配置文件
<?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-4.3.xsd"> <!-- 配置业务Bean -->
<bean id="helloWorldBusiness" class="roberto.growth.process.aop.HelloWorldBusiness" /> <!-- 配置切面Bean -->
<bean id="helloWorldBusinessAspect" class="roberto.growth.process.aop.HelloWorldBusinessAspect" /> <aop:config>
<!-- 配置一个切点 -->
<aop:pointcut id="sayHelloWorldPoint" expression="execution(public * roberto.growth.process.aop.HelloWorldBusiness.sayHelloWorld(..))" /> <!-- 配置通知类 -->
<aop:advisor advice-ref="helloWorldBusinessAspect" pointcut-ref="sayHelloWorldPoint" />
</aop:config>
</beans>
4.运行HelloWorldBusiness的sayHelloWorld方法输出结果为
执行sayHelloWorld方法前运行,参数为: JAVA
真正的业务方法执行啦~~~
执行方法返回后运行,参数为:JAVA 方法返回值为:Hello World JAVA
基于注解方式配置AOP
正常通知
1.编写业务类
@Component
public class HelloWorldBusiness {
public String sayHelloWorld(String language) {
String result = "Hello World " + language;
System.out.println("真正的业务方法执行啦~~~");
return result;
}
}
2.编写切面类
@Aspect
@Component
public class HelloWorldBusinessAspect {
@Pointcut("execution(public * roberto.growth.process.aop.HelloWorldBusiness.sayHelloWorld(..)) && args(language)")
public void sysHelloWorldPointCut(String language) { } @Before("sysHelloWorldPointCut(language)")
public void beforeSayHelloWorld(String language) {
System.out.println("执行方法前运行,参数为:" + language);
} @After("sysHelloWorldPointCut(language)")
public void afterSayHelloWorld(String language) {
System.out.println("执行方法后运行,参数为:" + language);
} @AfterReturning(pointcut = "sysHelloWorldPointCut(language)", returning = "result")
public void afterReturningSayHelloWorld(String language, String result) {
System.out.println("执行方法返回后运行,参数为:" + language + " 方法返回值为:" + result);
} @AfterThrowing(pointcut = "sysHelloWorldPointCut(language)", throwing = "e")
public void afterThrowingHelloWorld(String language, Throwable e) {
System.out.println("执行方法抛出异常后运行,参数为:" + language + "异常为:" + e);
}
}
3.编写配置类(使用EnableAspectJAutoProxy注解启用自动代理功能,即aspectJ的cglib代理方式)
@Configuration
@EnableAspectJAutoProxy
@ComponentScan(basePackages = "roberto.growth.process")
public class ApplicationConfig { }
4.运行HelloWorldBusiness的sayHelloWorld方法输出结果为
执行方法前运行,参数为:JAVA
真正的业务方法执行啦~~~
执行方法后运行,参数为:JAVA
执行方法返回后运行,参数为:JAVA 方法返回值为:Hello World JAVA
环绕通知
1.编写业务类
@Component
public class HelloWorldBusiness {
public String sayHelloWorld(String language) {
String result = "Hello World " + language;
System.out.println("真正的业务方法执行啦~~~");
return result;
}
}
2.编写切面类
@Aspect
@Component
public class HelloWorldBusinessAspect {
@Pointcut("execution(public * roberto.growth.process.aop.HelloWorldBusiness.sayHelloWorld(..))")
public void sysHelloWorldPointCut() { } @Around("sysHelloWorldPointCut()")
public void aroundSayHelloWorld(ProceedingJoinPoint joinPoint) {
String language = (String) joinPoint.getArgs()[0];
try {
System.out.println("执行方法前运行,参数为:" + language);
String result = (String) joinPoint.proceed();
System.out.println("执行方法后运行,参数为:" + language + " 方法返回值为:" + result);
} catch (Throwable e) {
System.out.println("执行方法抛出异常后运行,参数为:" + language + "异常为:" + e);
}
}
}
3.编写配置类(使用EnableAspectJAutoProxy注解启用自动代理功能,即aspectJ的cglib代理方式)
@Configuration
@EnableAspectJAutoProxy
@ComponentScan(basePackages = "roberto.growth.process")
public class ApplicationConfig { }
4.运行HelloWorldBusiness的sayHelloWorld方法输出结果为
执行方法前运行,参数为:JAVA
真正的业务方法执行啦~~~
执行方法后运行,参数为:JAVA 方法返回值为:Hello World JAVA
转载:https://blog.csdn.net/RobertoHuang/article/details/70148474
Spring AOP面向切面编程详解的更多相关文章
- 详细解读 Spring AOP 面向切面编程(二)
本文是<详细解读 Spring AOP 面向切面编程(一)>的续集. 在上篇中,我们从写死代码,到使用代理:从编程式 Spring AOP 到声明式 Spring AOP.一切都朝着简单实 ...
- 浅谈Spring AOP 面向切面编程 最通俗易懂的画图理解AOP、AOP通知执行顺序~
简介 我们都知道,Spring 框架作为后端主流框架之一,最有特点的三部分就是IOC控制反转.依赖注入.以及AOP切面.当然AOP作为一个Spring 的重要组成模块,当然IOC是不依赖于Spring ...
- spring AOP面向切面编程学习笔记
一.面向切面编程简介: 在调用某些类的方法时,要在方法执行前或后进行预处理或后处理:预处理或后处理的操作被封装在另一个类中.如图中,UserService类在执行addUser()或updateUse ...
- 【Spring系列】Spring AOP面向切面编程
前言 接上一篇文章,在上午中使用了切面做防重复控制,本文着重介绍切面AOP. 在开发中,有一些功能行为是通用的,比如.日志管理.安全和事务,它们有一个共同点就是分布于应用中的多处,这种功能被称为横切关 ...
- 从源码入手,一文带你读懂Spring AOP面向切面编程
之前<零基础带你看Spring源码--IOC控制反转>详细讲了Spring容器的初始化和加载的原理,后面<你真的完全了解Java动态代理吗?看这篇就够了>介绍了下JDK的动态代 ...
- Spring AOP 面向切面编程相关注解
Aspect Oriented Programming 面向切面编程 在Spring中使用这些面向切面相关的注解可以结合使用aspectJ,aspectJ是专门搞动态代理技术的,所以比较专业. ...
- Spring AOP 面向切面编程入门
什么是AOP AOP(Aspect Oriented Programming),即面向切面编程.众所周知,OOP(面向对象编程)通过的是继承.封装和多态等概念来建立一种对象层次结构,用于模拟公共行为的 ...
- 详细解读 Spring AOP 面向切面编程(一)
又是一个周末, 今天我要和大家分享的是 AOP(Aspect-Oriented Programming)这个东西,名字与 OOP 仅差一个字母,其实它是对 OOP 编程方式的一种补充,并非是取而代之. ...
- Spring Aop面向切面编程&&自动注入
1.面向切面编程 在程序原有纵向执行流程中,针对某一个或某一些方法添加通知,形成横切面的过程叫做面向切面编程 2.常用概念 原有功能:切点,pointcut 前置通知:在切点之前执行的功能,befor ...
随机推荐
- Spring AOP(面向切面示例)
什么是AOP?基本概念切面(aspect):横切关注点被模块化的特殊对象.通知(advice):切面必须要完成的工作.切面中的每个方向称之为通知.通知是在切面对象中的.目标(target):被通知的对 ...
- vue如何循环同一个echarts图表
因为我们知道echarts图表需要一个ID节点,所以我们循环echarts同一个图表时要考虑ID节点变化问题.废话不多说,直接上demo效果. 这里有一位分析师在不同的模拟组合,这时需求要在dialo ...
- New Concept English three (32)
26w/m 68 The salvage operation had been a complete failure. The small ship, Elkor, which had been se ...
- jQuery对象[0]倒底是什么?
s[0]倒底是什么?(s为jQuery对象)代码:var s=$("div"); alert(s.length);alert(s[0]); jQuery对象默认都有个0索引,s为j ...
- Discuz代码研究-编码规范
Discuz中的编码规范很值得PHP开发人员借鉴.里面既介绍了编码时代码标记,注释,书写规则,命名原则等方面基础的内容,对代码的安全性,性能,兼容性,代码重用,数据库设计,数据库性能及优化作了阐述,这 ...
- 基于tcp协议的粘包问题(subprocess、struct)
要点: 报头 固定长度bytes类型 1.粘包现象 粘包就是在获取数据时,出现数据的内容不是本应该接收的数据,如:对方第一次发送hello,第二次发送world,我放接收时,应该收两次,一次是hel ...
- 火狐下的GreaseMonkey和Chrome下的tampermonkey使用手记
说明:GreaseMonkey的作用是让我们浏览器运行我们自己写的脚本,而且是在后台一直不断的运行,听着就让人兴奋. [ps:他们当然可以创建名单对哪些网站作用或者排除哪些站点]: 开始了:Greas ...
- [HAL]5.中断里调用HAL_Delay()进入死循环的原因
中断里调用HAL_Delay()进入死循环的原因 摘自:http://blog.csdn.net/alwxkxk/article/details/47204677 CUBE生成的程序中, SysTi ...
- HihoCoder1041 国庆出游 树形DP第四题
小Hi和小Ho准备国庆期间去A国旅游.A国的城际交通比较有特色:它共有n座城市(编号1-n):城市之间恰好有n-1条公路相连,形成一个树形公路网.小Hi计划从A国首都(1号城市)出发,自驾遍历所有城市 ...
- js 预解析
前言 JavaScript是解释型语言是毋庸置疑的,但它是不是仅在运行时自上往下一句一句地解析的呢? 事实上或某种现象证明并不是这样的,通过<JavaScript权威指南>及网上相关资料了 ...