Spring学习之第一个AOP程序
IOC和AOP是Spring的两大基石,AOP(面向方面编程),也可称为面向切面编程,是一种编程范式,提供从另一个角度来考虑程序结构从而完善面向对象编程(OOP)。
在进行 OOP 开发时,都是基于对组件(比如类)进行开发,然后对组件进行组合,OOP 最大问题就是无法解耦组件进行开发,比如我们上边举例,而 AOP 就是为了克服这个问题而出现的,它来进行这种耦合的分离。AOP 为开发者提供一种进行横切关注点(比如日志关注点)分离并织入的机制,把横切关注点分离,然后通过某种技术织入到系统中,从而无耦合的完成了我们的功能。
1、AOP基本概念
- 连接点( Jointpoint) : 表示需要在程序中插入横切关注点的扩展点,连接点可能是类初始化、方法执行、 方法调用、字段调用或处理异常等等, Spring 只支持方法执行连接点, 在 AOP 中表示为“在哪里干” ;
- 切入点( Pointcut) : 选择一组相关连接点的模式, 即可以认为连接点的集合,Spring 支持 perl5 正则表达式和 AspectJ 切入点模式, Spring 默认使用 AspectJ 语法, 在 AOP 中表示为“在哪里干的集合” ;
- 通知( Advice) : 在连接点上执行的行为, 通知提供了在 AOP 中需要在切入点所选择的连接点处进行扩展现有行为的手段; 包括前置通知( before advice)、后置通知(after advice)、环绕通知( around advice), 在 Spring 中通过代理模式实现AOP,并通过拦截器模式以环绕连接点的拦截器链织入通知; 在 AOP 中表示为“干什么”;
- 方面/切面( Aspect): 横切关注点的模块化,可以认为是通知、引入和切入点的组合; 在 Spring 中可以使用 Schema 和@AspectJ 方式进行组织实现; 在 AOP 中表示为“在哪干和干什么集合” ;
- 引入( inter-type declaration) : 也称为内部类型声明, 为已有的类添加额外新的字段或方法, Spring 允许引入新的接口(必须对应一个实现)到所有被代理对象(目标对象) , 在 AOP 中表示为“干什么(引入什么) ” ;
- 目标对象( Target Object) : 需要被织入横切关注点的对象,即该对象是切入点选择的对象,需要被通知的对象,从而也可称为“被通知对象”;由于 Spring AOP通过代理模式实现,从而这个对象永远是被代理对象, 在 AOP 中表示为“对谁干” ;
- AOP 代理( AOP Proxy) : AOP 框架使用代理模式创建的对象,从而实现在连接点处插入通知(即应用切面) ,就是通过代理来对目标对象应用切面。在 Spring中, AOP 代理可以用 JDK 动态代理或 CGLIB 代理实现,而通过拦截器模型应用切面。
- 织入( Weaving) : 织入是一个过程,是将切面应用到目标对象从而创建出 AOP代理对象的过程, 织入可以在编译期、类装载期、运行期进行。
Spring有哪些通知类型呢?
- 前置通知( Before Advice) :在切入点选择的连接点处的方法之前执行的通知,该通知不影响正常程序执行流程(除非该通知抛出异常,该异常将中断当前方法链的执行而返回)。
- 后置通知( After Advice) : 在切入点选择的连接点处的方法之后执行的通知,包括如下类型的后置通知:
- 后置返回通知( After returning Advice) :在切入点选择的连接点处的方法正常执行完毕时执行的通知, 必须是连接点处的方法没抛出任何异常正常返回时才调用后置通知。
- 后置异常通知( After throwing Advice) : 在切入点选择的连接点处的方法抛出异常返回时执行的通知, 必须是连接点处的方法抛出任何异常返回时才调用异常通知。
- 后置最终通知( After finally Advice) : 在切入点选择的连接点处的方法返回时执行的通知,不管抛没抛出异常都执行,类似于 Java 中的 finally 块。
- 环绕通知( Around Advices): 环绕着在切入点选择的连接点处的方法所执行的通知,环绕通知可以在方法调用之前和之后自定义任何行为,并且可以决定是否执行连接点处的方法、替换返回值、抛出异常等等。
在 AOP 中,通过切入点选择目标对象的连接点,然后在目标对象的相应连接点处织入通知,而切入点和通知就是切面(横切关注点),而在目标对象连接点处应用切面的实现方式是通过 AOP 代理对象,如图所示。
2、AOP的HelloWorld程序
AOP代理就是 AOP框架通过代理模式创建的对象,Spring使用 JDK动态代理或 CGLIB代理来实现, Spring 缺省使用 JDK 动态代理来实现,从而任何接口都可被代理,如果被代理的对象实现不是接口将默认使用 CGLIB 代理,不过 CGLIB 代理当然也可应用到接口。AOP 代理的目的就是将切面织入到目标对象。
新建工程,导入Spring中对应的包,最后引入的jar包如下所示(有些包spring的lib下没有,需要另外下载):
(1)定义目标接口
package com.log; public interface IHelloWorldService {
public void sayHello();
}
(2)定义目标接口实现类
package com.log; public class HelloWorldService implements IHelloWorldService {
@Override
public void sayHello() {
System.out.println("---hello world---");
}
}
(3)定义切面支持类
package com.log; public class HelloWorldAspect {
public void beforeAdvice() {
System.out.println("---before advice---");
} public void afterAdvice() {
System.out.println("---after advice---");
}
}
(4)在XML中进行配置
<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-2.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"> <!-- 配置目标类 -->
<bean id="helloWorldService" class="com.log.HelloWorldService"/>
<!-- 配置切面 -->
<bean id="aspect" class="com.log.HelloWorldAspect"/>
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* com.log..*.*(..))"/>
<!-- aop:aspect的ref引用切面支持类的方法 -->
<aop:aspect ref="aspect">
<aop:before pointcut-ref="pointcut"
method="beforeAdvice"/>
<aop:after pointcut-ref="pointcut"
method="afterAdvice"/>
</aop:aspect>
</aop:config>
</beans>
切入点使用<aop:config>标签下的<aop:pointcut>配置, expression属性用于定义切入点模式,默认是AspectJ语法,“ execution(* cn.javass..*.*(..))”表示匹配cn.javass包及子包下的任何方法执行。关于expression属性如何配置请点击:expression配置
切面使用<aop:config>标签下的<aop:aspect>标签配置,其中“ ref”用来引用切面支持类的方法。
前置通知使用<aop:aspect>标签下的<aop:before>标签来定义, pointcut-ref属性用于引用切入点Bean, 而method用来引用切面通知实现类中的方法,该方法就是通知实现,即在目标类方法执行之前调用的方法。
最终通知使用<aop:aspect>标签下的<aop:after >标签来定义,切入点除了使用pointcut-ref属性来引用已经存在的切入点,也可以使用pointcut属性来定义,如pointcut="execution(* cn.javass..*.*(..))", method属性同样是指定通知实现,即在目标类方法执行之后调用的方法。
(5)测试运行
package com.log; import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class AopTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("aopBean.xml");
IHelloWorldService hello = context.getBean("helloWorldService", IHelloWorldService.class);
hello.sayHello(); HelloWorldAspect advice = context.getBean("aspect", HelloWorldAspect.class);
advice.beforeAdvice();
}
}
(6)输出结果
参考资料
1、跟我学SpringMVC目录汇总贴、PDF下载、源码下载
Spring学习之第一个AOP程序的更多相关文章
- swift学习:第一个swift程序
原文:swift学习:第一个swift程序 最近swift有点火,赶紧跟上学习.于是,个人第一个swift程序诞生了... 新建项目
- Spring学习之第一个Spring MVC程序(IDEA开发环境)
回顾Java平台上Web开发历程来看,从Servlet出现开始,到JSP繁盛一时,然后是Servlet+JSP时代,最后演化为现在Web开发框架盛行的时代.一般接触到一个新的Web框架,都会想问这个框 ...
- Spring学习记录(十二)---AOP理解和基于注解配置
Spring核心之二:AOP(Aspect Oriented Programming) --- 面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软 ...
- Spring学习笔记IOC与AOP实例
Spring框架核心由两部分组成: 第一部分是反向控制(IOC),也叫依赖注入(DI); 控制反转(依赖注入)的主要内容是指:只描述程序中对象的被创建方式但不显示的创建对象.在以XML语言描述的配置文 ...
- Spring学习之旅(五)--AOP
什么是 AOP AOP(Aspect-OrientedProgramming,面向方面编程),可以说是 OOP(Object-Oriented Programing,面向对象编程)的补充和完善. OO ...
- Spring学习(八)AOP详解
文章更新时间:2020/04/06 一.一个例子 在上面的例子中,包租婆的核心业务就是签合同,收房租,那么这就够了,灰色框起来的部分都是重复且边缘的事,交给中介商就好了,这就是 AOP 的一个思想:让 ...
- python flask框架学习(二)——第一个flask程序
第一个flask程序 学习自:知了课堂Python Flask框架——全栈开发 1.用pycharm新建一个flask项目 2.运行程序 from flask import Flask # 创建一个F ...
- JavaWeb学习系列——第一个JavaWeb程序
创建JavaWeb项目 Eclipse中新建一个Dynamic Web Project 指定项目名称.依赖环境 勾选生成web.xml选项 更改项目编译输出目录,项目右键 ->propertie ...
- c++学习笔记---03---从一个小程序说起2
从一个小程序说起2 要求:编写一个程序,要求用户输入一串整数和任意数目的空格,这些整数必须位于同一行中,但允许出现在该行中的任何位置.当用户按下键盘上的"Enter"键时,数据输入 ...
随机推荐
- Select-or-Die:灵活的 jQuery 下拉列表插件
Select-or-Die 是一个 jQuery 插件,用来自定义下拉列表(Select)元素.原生的下拉选择元素在各个浏览器的默认样式差异很多,而且自定义样式很困难,因此 Web 开发人员喜欢使用插 ...
- ABAP中的同步和异步调用
ABAP 的 CALL FUNCTION 类似于 Java/.NET 中的本地或远程方法调用.CALL FUNCTION 可以分为四种:1. Synchronous RFC (sRFC) - 同步调用 ...
- 使用MDK3探测隐藏SSID名称
先将网卡设置为监听模式. airmon-ng start wlan0 扫描附近无线网络,找出隐藏SSID的AP. airodump-ng wlan0mon 这里用下图搜到的第一个隐藏SSID做测试. ...
- 错误解决:SharePoint Designer 2010编辑后,出现数据源控件未能执行插入命令,data source control failed to execute the insert command
打了SharePoint 2010 最新的SP 2的补丁,但是使用SharePoint Designer 2010 定义任何一个列表的“插入视图”时,总是出现标题那样的错误: 数据源控件未能执行插入命 ...
- 阿里云上部署 centos+nodejs+mongodb
先执行 yum -y update nginx 安装 yum -y install nginx 设置开机启动 chkconfig nginx on nodejs 安装: yum install nod ...
- XMPP学习——2、用户登录
最近在学习XMPP的使用,打算完成一个完整较为完整地Demo示例,通过这个示例掌握xmpp的使用与开发.同时打算在这个示例中学习使用一下其他的开源类库,在此作为记录学习. 包括服务器端--Openfi ...
- NDK-JNI实战教程(二) JNI官方中文资料
声明 设计概述 JNI接口函数和指针 加载和链接本地方法 解析本地方法名 本地方法的参数 引用Java对象 全局和局部引用 实现局部引用 访问Java对象 访问基本类型数组 访问域和方法 报告编程错误 ...
- iOS小型计算器
// // ViewController.m // 计算器 //屏幕的宽和高 #define SCREEN_W self.view.frame.size.width #define SCREEN_ ...
- Mac电脑清理硬盘"其他"
作为一个MacBook的使用者,无不感受到苹果对于系统和硬件的完美匹配. 苹果电脑不适合玩游戏,所以我只用它开发iOS使用.电脑里除了Xcode和常用办公软件与通讯软件以外,我没有装其他的任何大应用. ...
- 持续集成 .Net手册--提升开发效率和质量
参考:http://blog.csdn.net/chelsea/article/details/132525 持续集成 .Net手册 一.概念 Martin Fowler的文章:Continuous ...