- 浏览: 513343 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (563)
- 工作经验 (12)
- 数据库 (13)
- Servlet (10)
- Struts2 (1)
- Spring (25)
- Eclipse (5)
- Hibernate (5)
- Eclips (8)
- HTTP (7)
- J2EE (21)
- EHcache (1)
- HTML (11)
- 工具插件使用 (20)
- JPA (2)
- 杂谈 (17)
- 数据结构与算法 (3)
- Cloud Foundry (1)
- 安全 (10)
- J2SE (57)
- SQL (9)
- DB2 (6)
- 操作系统 (2)
- 设计模式 (1)
- 版本代码管理工具 (13)
- 面试 (10)
- 代码规范 (3)
- Tomcat (12)
- Ajax (5)
- 异常总结 (11)
- REST (2)
- 云 (2)
- RMI (3)
- SOA (1)
- Oracle (12)
- Javascript (20)
- jquery (7)
- JSP自定义标签 (2)
- 电脑知识 (5)
- 浏览器 (3)
- 正则表达式 (3)
- 建站解决问题 (38)
- 数据库设计 (3)
- git (16)
- log4j (1)
- 每天100行代码 (1)
- socket (0)
- java设计模式 耿祥义著 (0)
- Maven (14)
- ibatis (7)
- bug整理 (2)
- 邮件服务器 (8)
- Linux (32)
- TCP/IP协议 (5)
- java多线程并发 (7)
- IO (1)
- 网页小工具 (2)
- Flash (2)
- 爬虫 (1)
- CSS (6)
- JSON (1)
- 触发器 (1)
- java并发 (12)
- ajaxfileupload (1)
- js验证 (1)
- discuz (2)
- Mysql (14)
- jvm (2)
- MyBatis (10)
- POI (1)
- 金融 (1)
- VMWare (0)
- Redis (4)
- 性能测试 (2)
- PostgreSQL (1)
- 分布式 (2)
- Easy UI (1)
- C (1)
- 加密 (6)
- Node.js (1)
- 事务 (2)
- zookeeper (3)
- Spring MVC (2)
- 动态代理 (3)
- 日志 (2)
- 微信公众号 (2)
- IDEA (1)
- 保存他人遇到的问题 (1)
- webservice (11)
- memcached (3)
- nginx (6)
- 抓包 (1)
- java规范 (1)
- dubbo (3)
- xwiki (1)
- quartz (2)
- 数字证书 (1)
- spi (1)
- 学习编程 (6)
- dom4j (1)
- 计算机系统知识 (2)
- JAVA系统知识 (1)
- rpcf (1)
- 单元测试 (2)
- php (1)
- 内存泄漏cpu100%outofmemery (5)
- zero_copy (2)
- mac (3)
- hive (3)
- 分享资料整理 (0)
- 计算机网络 (1)
- 编写操作系统 (1)
- springboot (1)
最新评论
-
masuweng:
亦论一次OutOfMemoryError的定位与解错 -
变脸小伙:
引用[color=red][/color]百度推广中运用的技术 ...
Spring 3 mvc中返回pdf,json,xml等不同的view -
Vanillva:
不同之处是什么??
Mybatis中的like查询 -
thrillerzw:
转了。做个有理想的程序员
有理想的程序员必须知道的15件事 -
liujunhui1988:
觉得很有概括力
15 个必须知道的 Java 面试问题(2年工作经验)
源:http://blog.csdn.net/zuyi532/article/details/7992323
评:
AOP实现原理
AOP的实现原理可以看作是Proxy/Decorator设计模式的泛化。我们先来看Proxy模式的简单例子。
Proxy {
innerObject; // 真正的对象
f1() {
// 做一些额外的事情
innerObject.f1(); // 调用真正的对象的对应方法
// 做一些额外的事情
}
}
在Python、Ruby等动态类型语言中,只要实现了f1()方法的类,都可以被Proxy包装。在Java等静态类型语言中,则要求Proxy和被包装对象实现相同的接口。动态语言实现Proxy模式要比静态语言容易得多,动态语言实现AOP也要比静态语言容易得多。假设我们用Proxy包装了10个类,我们通过调用Proxy的f1()方法来调用这10个类的f1()方法,这样,所有的f1()调用都会执行同样的一段“额外的工作”,从而实现了“所有被Proxy包装的类,都执行一段同样的额外工作”的任务。这段“额外的工作”可能是进行日志记录,权限检查,事务管理等常见工作。
Proxy模式是可以叠加的。我们可以定义多种完成特定方面任务(Aspect),比如,我们可以定义LogProxy、SecurityProxy、TransactionProxy,分别进行日志管理、权限管理、事务管理。
LogProxy {
f1(){
// 记录方法进入信息
innerObject.f1();// 调用真正的对象的对应方法
// 记录方法退出信息
}
}
SecurityProxy {
f1(){
// 进行权限验证
innerObject.f1();// 调用真正的对象的对应方法
}
}
TransactonProxy {
f1(){
Open Transaction
innerObject.f1();// 调用真正的对象的对应方法
Close Transaction
}
}
根据AOP的惯用叫法,上述的这些Proxy也叫做Advice。这些Proxy(or Advice)可以按照一定的内外顺序套起来,最外面的Proxy会最先执行。包装f1()方法,也叫做截获(Intercept)f1()方法。Proxy/Advice有时候也叫做Interceptor。
看到这里,读者可能会产生两个问题。
问题一:上述代码采用的Proxy模式只是面向对象的特性,怎么会扯上一个新概念“面向方面(AOP)”呢?
问题二:Proxy模式虽然避免了重复“额外工作”代码的问题,但是,每个相关类都要被Proxy包装,这个工作也是很烦人。AOP Proxy如何能在应用程序中大规模使用呢?
下面我们来解答着两个问题。
对于问题一,我们来看一个复杂一点的例子。假设被包装对象有f1()和f2()两个方法都要被包装。
RealObject{
f1() {…}
f2() {…}
}
这个时候,我们应该如何做?难道让Proxy也定义f1()和f2()两个方法?就象下面代码这样?
Proxy {
innerObject; // 真正的对象
f1() {
// 做一些额外的事情
innerObject.f1(); // 调用真正的对象的对应方法
// 做一些额外的事情
}
f2() {
// 做一些额外的事情
innerObject.f2(); // 调用真正的对象的对应方法
// 做一些额外的事情
}
}
这样做有几个不利之处。一是会造成代码重复,Proxy的f1()和f2()里面的“做一些额外的事情”代码重复。二是难以扩展,被包装对象可能有多个不同的方法,不同的被包装对象需要被包装的方法也可能不同。现在的问题就变成,“Proxy如何才能包装截获任何类的任何方法?”
答案呼之欲出。对,就是Reflection。Java、Python、Ruby都支持Reflection,都支持Method(方法)对象。那么我们就利用Method Reflection编写一个能够解惑任何类的任何方法的Proxy/Advice/Interceptor。
MethodInterceptor{
around( method ){
// 做些额外的工作
method.invoke(…); // 调用真正的对象方法
// 做些额外的工作
}
}
上述的MethodInterceptor就可以分别包装和截获f1()和f2()两个方法。
这里的method参数就是方法对象,在Java、Ruby等面向对象语言中,需要用Reflection获取方法对象。这个方法对象就相当于函数式编程的函数对象。在函数式编程中,函数对象属于“一等公民”,函数对象的获取不需要经过Reflection机制。所以,函数式编程对AOP的支持,比面向对象编程更好。由此我们看到,AOP对应的问题领域确实超出了OOP的力所能及的范围。OOP只能处理同一个类体系内的同一个方法签名的截获和包装工作,一旦涉及到一个类的多个不同方法,或者多个不同类体系的不同方法,OOP就黔驴技穷,无能为力了。
使用Method Reflection的方式截获任何方法对象,是AOP的常用实现手段之一。另一个常见手段就是自动代码生成了。这也回答了前面提出的问题二——如何在应用系统中大规模使用AOP。
Proxy Pattern + Method Reflection + 自动代码生成这样一个三元组合,就是AOP的基本实现原理。Proxy Pattern 和 Method Reflection,前面已经做了阐述,下面我们来讲解自动代码生成。
首先,AOP需要定义一种Aspect描述的DSL。Aspect DSL主要用来描述这样的内容:“用TransactionProxy包装截获business目录下的所有类的公共业务方法”、“ 用SecurityProxy包装截获所有Login/Logout开头的类的所有公共方法”、“用LogProxy包装截获所有文件的所有方法”等等。Aspect DSL的形式有多种多样。有的是一种类似Java的语法,比如AspectJ;有的是XML格式或者各种脚本语言,比如,Spring AOP等。
有了Aspect DSL,AOP处理程序就可以生成代码了。AOP生成代码有三种可能方式:
(1)静态编译时期,源代码生成。为每个符合条件的类方法产生对应的Proxy对象。AspectJ以前就是这种方式。
(2)静态编译时期,处理编译后的字节码。Java、Python之类的虚拟机语言都有一种中间代码(Java的中间代码叫做字节码),AOP处理程序可以分析字节码,并直接产生字节码形式的Proxy。这种方式也叫做静态字节码增强。AspectJ也支持这种方式。Java有一些开源项目,比如 ASM、Cglib等,可以分析并生成Java字节码。这些开源项目不仅可以静态分析增强字节码,还可以在程序运行期动态分析增强字节码。很多AOP项目,比如Spring AOP,都采用ASM/Cglib处理字节码。
(3)动态运行时期,即时处理装载到虚拟机内部的类结构字节码。这也叫做动态增强。比如,Spring AOP。如前所述,Spring AOP使用ASM/Cglib之类的处理字节码的开源项目。Java运行库本身也提供了类似于ASM/Cglib的简单的动态处理字节码的API,叫做 Dynamic Proxy。
以上就是AOP的实现原理:Proxy Pattern + Method Reflection + Aspect DSL + 自动代码生成。
总体来说,实现AOP的便利程度,函数式编程语言 > 动态类型语言 > 静态类型语言。当然,这个不等式并不是绝对的。有些动态类型语言提供了丰富强大的语法特性,实现AOP的便利程度,可能要超过函数式编程语言。
评:
AOP实现原理
AOP的实现原理可以看作是Proxy/Decorator设计模式的泛化。我们先来看Proxy模式的简单例子。
Proxy {
innerObject; // 真正的对象
f1() {
// 做一些额外的事情
innerObject.f1(); // 调用真正的对象的对应方法
// 做一些额外的事情
}
}
在Python、Ruby等动态类型语言中,只要实现了f1()方法的类,都可以被Proxy包装。在Java等静态类型语言中,则要求Proxy和被包装对象实现相同的接口。动态语言实现Proxy模式要比静态语言容易得多,动态语言实现AOP也要比静态语言容易得多。假设我们用Proxy包装了10个类,我们通过调用Proxy的f1()方法来调用这10个类的f1()方法,这样,所有的f1()调用都会执行同样的一段“额外的工作”,从而实现了“所有被Proxy包装的类,都执行一段同样的额外工作”的任务。这段“额外的工作”可能是进行日志记录,权限检查,事务管理等常见工作。
Proxy模式是可以叠加的。我们可以定义多种完成特定方面任务(Aspect),比如,我们可以定义LogProxy、SecurityProxy、TransactionProxy,分别进行日志管理、权限管理、事务管理。
LogProxy {
f1(){
// 记录方法进入信息
innerObject.f1();// 调用真正的对象的对应方法
// 记录方法退出信息
}
}
SecurityProxy {
f1(){
// 进行权限验证
innerObject.f1();// 调用真正的对象的对应方法
}
}
TransactonProxy {
f1(){
Open Transaction
innerObject.f1();// 调用真正的对象的对应方法
Close Transaction
}
}
根据AOP的惯用叫法,上述的这些Proxy也叫做Advice。这些Proxy(or Advice)可以按照一定的内外顺序套起来,最外面的Proxy会最先执行。包装f1()方法,也叫做截获(Intercept)f1()方法。Proxy/Advice有时候也叫做Interceptor。
看到这里,读者可能会产生两个问题。
问题一:上述代码采用的Proxy模式只是面向对象的特性,怎么会扯上一个新概念“面向方面(AOP)”呢?
问题二:Proxy模式虽然避免了重复“额外工作”代码的问题,但是,每个相关类都要被Proxy包装,这个工作也是很烦人。AOP Proxy如何能在应用程序中大规模使用呢?
下面我们来解答着两个问题。
对于问题一,我们来看一个复杂一点的例子。假设被包装对象有f1()和f2()两个方法都要被包装。
RealObject{
f1() {…}
f2() {…}
}
这个时候,我们应该如何做?难道让Proxy也定义f1()和f2()两个方法?就象下面代码这样?
Proxy {
innerObject; // 真正的对象
f1() {
// 做一些额外的事情
innerObject.f1(); // 调用真正的对象的对应方法
// 做一些额外的事情
}
f2() {
// 做一些额外的事情
innerObject.f2(); // 调用真正的对象的对应方法
// 做一些额外的事情
}
}
这样做有几个不利之处。一是会造成代码重复,Proxy的f1()和f2()里面的“做一些额外的事情”代码重复。二是难以扩展,被包装对象可能有多个不同的方法,不同的被包装对象需要被包装的方法也可能不同。现在的问题就变成,“Proxy如何才能包装截获任何类的任何方法?”
答案呼之欲出。对,就是Reflection。Java、Python、Ruby都支持Reflection,都支持Method(方法)对象。那么我们就利用Method Reflection编写一个能够解惑任何类的任何方法的Proxy/Advice/Interceptor。
MethodInterceptor{
around( method ){
// 做些额外的工作
method.invoke(…); // 调用真正的对象方法
// 做些额外的工作
}
}
上述的MethodInterceptor就可以分别包装和截获f1()和f2()两个方法。
这里的method参数就是方法对象,在Java、Ruby等面向对象语言中,需要用Reflection获取方法对象。这个方法对象就相当于函数式编程的函数对象。在函数式编程中,函数对象属于“一等公民”,函数对象的获取不需要经过Reflection机制。所以,函数式编程对AOP的支持,比面向对象编程更好。由此我们看到,AOP对应的问题领域确实超出了OOP的力所能及的范围。OOP只能处理同一个类体系内的同一个方法签名的截获和包装工作,一旦涉及到一个类的多个不同方法,或者多个不同类体系的不同方法,OOP就黔驴技穷,无能为力了。
使用Method Reflection的方式截获任何方法对象,是AOP的常用实现手段之一。另一个常见手段就是自动代码生成了。这也回答了前面提出的问题二——如何在应用系统中大规模使用AOP。
Proxy Pattern + Method Reflection + 自动代码生成这样一个三元组合,就是AOP的基本实现原理。Proxy Pattern 和 Method Reflection,前面已经做了阐述,下面我们来讲解自动代码生成。
首先,AOP需要定义一种Aspect描述的DSL。Aspect DSL主要用来描述这样的内容:“用TransactionProxy包装截获business目录下的所有类的公共业务方法”、“ 用SecurityProxy包装截获所有Login/Logout开头的类的所有公共方法”、“用LogProxy包装截获所有文件的所有方法”等等。Aspect DSL的形式有多种多样。有的是一种类似Java的语法,比如AspectJ;有的是XML格式或者各种脚本语言,比如,Spring AOP等。
有了Aspect DSL,AOP处理程序就可以生成代码了。AOP生成代码有三种可能方式:
(1)静态编译时期,源代码生成。为每个符合条件的类方法产生对应的Proxy对象。AspectJ以前就是这种方式。
(2)静态编译时期,处理编译后的字节码。Java、Python之类的虚拟机语言都有一种中间代码(Java的中间代码叫做字节码),AOP处理程序可以分析字节码,并直接产生字节码形式的Proxy。这种方式也叫做静态字节码增强。AspectJ也支持这种方式。Java有一些开源项目,比如 ASM、Cglib等,可以分析并生成Java字节码。这些开源项目不仅可以静态分析增强字节码,还可以在程序运行期动态分析增强字节码。很多AOP项目,比如Spring AOP,都采用ASM/Cglib处理字节码。
(3)动态运行时期,即时处理装载到虚拟机内部的类结构字节码。这也叫做动态增强。比如,Spring AOP。如前所述,Spring AOP使用ASM/Cglib之类的处理字节码的开源项目。Java运行库本身也提供了类似于ASM/Cglib的简单的动态处理字节码的API,叫做 Dynamic Proxy。
以上就是AOP的实现原理:Proxy Pattern + Method Reflection + Aspect DSL + 自动代码生成。
总体来说,实现AOP的便利程度,函数式编程语言 > 动态类型语言 > 静态类型语言。当然,这个不等式并不是绝对的。有些动态类型语言提供了丰富强大的语法特性,实现AOP的便利程度,可能要超过函数式编程语言。
发表评论
-
使用Spring+Junit+Mockito做代码自测
2019-05-29 15:27 503源:https://blog.csdn.net/z19917 ... -
在同一个类中调用另一个方法没有触发 Spring AOP 的问题
2017-08-24 17:22 574源:https://segmentfault.com/a/11 ... -
Spring Transaction属性之Propagation
2016-08-10 17:09 546源:http://blog.csdn.net/kiwi_cod ... -
循环依赖检测方法 spring源码方法
2016-07-06 18:58 1165场景:checkForAliasCircle(name, al ... -
Spring的Quartz定时器同一时刻重复执行二次的问题解决
2016-03-11 18:27 1002源:http://www.linuxidc.com/Linux ... -
spring factory-method
2016-03-01 11:22 485源:http://blog.sina.com.cn/s/blo ... -
spring中lazy-init详解
2016-02-29 17:01 776源:http://blog.csdn.net/fhx0 ... -
Spring Refresh Application Context
2015-12-13 14:48 861源:http://techdive.in/spring/spr ... -
spring context 扫描与 mvc扫描类 区分开包
2015-07-15 13:23 6091.applicationContext.xml <!- ... -
为什么免费代理是“免费”的?
2015-07-09 21:13 589源:http://blog.jobbole.com/87970 ... -
Filter中注入spring
2015-07-09 10:45 508源:http://zy116494718.iteye.com/ ... -
获取spring的ApplicationContext几种方式
2015-06-24 15:35 696源:http://blog.sina.com.cn/s/blo ... -
spring获取webapplicationcontext,applicationcontext几种方法详解
2015-04-02 16:38 465源:http://www.blogjava.net/Todd/ ... -
Spring+Mybatis整合事务不起作用之解决方案汇总
2014-12-29 21:36 1350源:http://blog.csdn.net/walkerjo ... -
context:component-scan扫描使用上的容易忽略的use-default-filters
2014-12-29 21:29 448源:http://jinnianshilongnian.ite ... -
Spring线程池开发实战
2014-12-12 10:44 498源:http://blog.csdn.net/chszs/ar ... -
JVM技术 反射与动态代理
2014-05-11 18:36 420源:http://www.educity.cn/it/sun/ ... -
Spring 3 mvc中返回pdf,json,xml等不同的view
2014-05-09 12:11 1039源:http://jackyrong.iteye.com/bl ... -
使用Spring MVC统一异常处理实战
2014-05-04 00:00 524源:http://cgs1999.iteye.com/blog ... -
spring配置文件异常
2013-11-26 10:53 903源:http://wodar.iteye.com/blog/ ...
相关推荐
本文将详细解析Spring AOP的三种实现方式,帮助你深入理解这一重要概念。 首先,理解AOP的基本概念至关重要。AOP是一种编程范式,它允许开发者定义“切面”,即关注点的模块化,如日志、事务管理等。这些切面可以...
在IT领域,Spring框架是Java开发中的重要组成部分,特别是其AOP(面向切面编程)模块,它允许开发者实现横切关注点,如日志、事务...理解并掌握这四种方式,将有助于我们更好地利用Spring AOP来优化和解耦我们的代码。
在C#中,实现AOP的方法多种多样,以下将详细介绍几种常见的实现方式。 1. **静态织入**: 静态织入是在编译时完成的,它通过编译器或者编译插件(如PostSharp)在目标类的代码中插入拦截逻辑。这种方式的优点是...
AOP(Aspect Oriented Programming,面向切面编程)是Spring框架中的一个重要概念,它提供了一种将关注点(如日志、事务管理等)与核心业务逻辑分离的方式,从而实现代码的模块化和可重用性。AOP通过定义切面...
本篇文章将详细探讨Spring实现AOP的四种主要方法:基于代理的方式、基于AspectJ的注解方式、基于XML的AOP配置以及基于Java的AOP配置。 1. 基于代理的实现 Spring的AOP支持两种代理类型:JDK动态代理和CGLIB代理。...
Spring AOP提供了一种声明性的方式来实现这些关注点,而无需侵入核心业务逻辑。通过定义切面和通知,我们可以把通用功能注入到应用程序的不同部分。 接下来,Ehcache是一个流行的Java缓存解决方案,它提供了本地...
在实际开发中,理解并掌握这四种AOP实现方式对于编写高效、灵活的代码至关重要。Spring的AOP特性使得我们能够更好地组织代码,将横切关注点与业务逻辑分离,从而提升代码的可重用性和可测试性。在学习和应用这些知识...
以上四种方式各有优缺点,选择哪种取决于具体的应用场景和需求。Javassist和CGLIB适用于对非接口类的代理,而Instrumentation则提供了更底层的字节码操作能力,适用于高级的定制需求。Dynamic Proxy则适合处理基于...
在实际项目中,理解Spring 4的AOP源代码有助于我们更好地定制和优化AOP功能,同时也能加深对Spring框架内部机制的理解。通过阅读源代码,我们可以学习到如何利用AOP来提高代码的复用性和可维护性,使我们的应用程序...
在 Spring 中,AOP 的实现主要依赖于代理模式,有两种代理方式:JDK 动态代理和 CGLIB 动态代理。 JDK 动态代理是基于接口的,它要求被代理的目标对象必须实现至少一个接口。Spring 使用 `java.lang.reflect.Proxy`...
本文将详细介绍Spring实现AOP的四种方式,包括基于代理的经典方式、@AspectJ注解驱动、纯POJO切面以及注入式AspectJ切面。 首先,理解AOP的基本概念: 1. **通知(Advice)**:通知定义了切面在何时执行,Spring支持...
Spring AOP,全称Spring Aspect-Oriented Programming(面向切面编程),是Spring框架的重要组成部分,它提供了一种模块化和声明式的方式来处理系统中的交叉关注点,如日志、事务管理、性能监控等。在Spring AOP中,...
Spring通过动态代理来实现AOP,它支持两种代理方式:JDK动态代理和CGLIB代理。 1. JDK动态代理:当目标类实现了至少一个接口时,Spring会使用java.lang.reflect.Proxy创建一个代理对象,该代理对象在调用接口方法时...
JBoss AOP是JBoss应用服务器的一个组成部分,它提供了一种在JVM级别进行切面织入的方式。JBoss AOP同样支持编译时和运行时的编织,但它更侧重于服务器端的事务管理和安全性等企业级服务。由于其与JBoss的紧密集成,...
面向切面编程(AOP)是一种编程范式,旨在将横切关注点(如日志、安全等)与业务逻辑分离,从而提高模块化。AOP通过预定义的“切面”对横切关注点进行模块化,从而可以在不修改业务逻辑代码的情况下增加新功能。动态...
综上所述,spring AOP依赖的这三个jar包构成了Spring框架面向切面编程的基础,它们共同协作,提供了便捷、高效和强大的AOP能力,帮助开发者实现代码的解耦,提高可维护性和复用性。在实际开发中,理解并熟练运用这些...
然而,使用纯C++实现AOP是有局限性的,例如,可能需要更复杂的代码结构,并且难以实现一些特定的AOP特性。AspectC++等工具的出现,就是为了提供更专门的语言机制来应对这些挑战,使得在C++中实施AOP变得更加直接和...
Spring AOP(Aspect Oriented Programming,面向切面编程)是Spring框架中的一个重要组件,它提供了一种在不修改原有代码的情况下,通过预编译方式和运行期动态代理实现程序功能统一维护的一种技术。AOP的核心思想是...
总的来说,AOP是面向对象编程的一种补充,它提供了一种更灵活的方式来组织和管理代码,减少了重复工作,提高了代码质量。在Java开发中,了解和掌握AOP的概念和实现方式对于提升编程效率和软件设计能力大有裨益。
本资源主要涵盖了静态代理和动态代理两种常见类型的代理模式,以及Spring AOP中动态代理的三种配置方式。以下是详细的知识点解析: ### 静态代理 静态代理是程序员手动创建代理类并实现相同接口的方式。代理类和...