Java AOP知识详细介绍

发布时间 - 2026-01-10 22:36:30    点击率:

Java AOP

AOP知识整理

AOP(Aspect-Oriented Programming):面向切面的编程。OOP(Object-Oriented Programming)面向对象的编程。对于OOP我们已经再熟悉不过了,对于AOP,可能我们会觉得是一种新特性,其实AOP是对OOP的一种补充,OOP面向的是纵向编程,继承、封装、多态是其三大特性,而AOP是面向横向的编程。

面向切面编程(AOP)通过提供另外一种思考程序结构的途经来弥补面向对象编程(OOP)的不足。在OOP中模块化的关键单元是类(classes),而在AOP中模块化的单元则是切面。切面能对关注点进行模块化,例如横切多个类型和对象的事务管理。
AOP框架是spring的一个重要组成部分。但是Spring IoC容器并不依赖于AOP,这意味着你有权利选择是否使用AOP,AOP做为Spring IoC容器的一个补充,使它成为一个强大的中间件解决方案。

AOP在Spring Framework中的作用

  • 提供声明式企业服务,特别是为了替代EJB声明式服务。最重要的服务是声明*务管理(这个我想是AOP使用最多的一处了)。
  • 允许用户实现自定义切面,用AOP来完善OOP的使用。

1.AOP概念:

学习AOP,当然得先了解一下其众多的概念性术语:

  • 切面(Aspect):一个关注点的模块化,这个关注点可能会横切多个对象。事务管理是J2EE应用中一个关于横切关注点的很好的例子。在Spring AOP中,切面可以使用基于模式)或者基于@Aspect注解的方式来实现。
  • 连接点(Joinpoint):在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候。在Spring AOP中,一个连接点总是表示一个方法的执行。
  • 通知(Advice):在切面的某个特定的连接点上执行的动作。其中包括了“around”、“before”和“after”等不同类型的通知(通知的类型将在后面部分进行讨论)。许多AOP框架(包括Spring)都是以拦截器做通知模型,并维护一个以连接点为中心的拦截器链。
  • 切入点(Pointcut):匹配连接点的断言。通知和一个切入点表达式关联,并在满足这个切入点的连接点上运行(例如,当执行某个特定名称的方法时)。切入点表达式如何和连接点匹配是AOP的核心:Spring缺省使用AspectJ切入点语法。
  • 引入(Introduction):用来给一个类型声明额外的方法或属性(也被称为连接类型声明(inter-type declaration))。Spring允许引入新的接口(以及一个对应的实现)到任何被代理的对象。例如,你可以使用引入来使一个bean实现IsModified接口,以便简化缓存机制。
  • 目标对象(Target Object): 被一个或者多个切面所通知的对象。也被称做被通知(advised)对象。 既然Spring AOP是通过运行时代理实现的,这个对象永远是一个被代理(proxied)对象。
  • AOP代理(AOP Proxy):AOP框架创建的对象,用来实现切面契约(例如通知方法执行等等)。在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理。
  • 织入(Weaving):把切面连接到其它的应用程序类型或者对象上,并创建一个被通知的对象。这些可以在编译时(例如使用AspectJ编译器),类加载时和运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。

通知类型:

  • 前置通知(Before advice):在某连接点之前执行的通知,但这个通知不能阻止连接点之前的执行流程(除非它抛出一个异常)。
  • 后置通知(After returning advice):在某连接点正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回。
  • 异常通知(After throwing advice):在方法抛出异常退出时执行的通知。
  • 最终通知(After (finally) advice):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。
  • 环绕通知(Around Advice):包围一个连接点的通知,如方法调用。这是最强大的一种通知类型。环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它自己的返回值或抛出异常来结束执行。

环绕通知是最常用的通知类型。和AspectJ一样,Spring提供所有类型的通知,我们推荐你使用尽可能简单的通知类型来实现需要的功能。例如,如果你只是需要一个方法的返回值来更新缓存,最好使用后置通知而不是环绕通知,尽管环绕通知也能完成同样的事情。用最合适的通知类型可以使得编程模型变得简单,并且能够避免很多潜在的错误。比如,你不需要在JoinPoint上

调用用于环绕通知的proceed()方法,就不会有调用的问题。

在这里,基于@AspectJ的AOP我就不多写了,因为我更青睐于Spring中使用ProxyFactoryBean创建AOP代理。

2.使用ProxyFactoryBean创建AOP代理:

在Spring里创建一个AOP代理的基本方法是使用org.springframework.aop.framework.ProxyFactoryBean。 这个类对应用的切入点和通知提供了完整的控制能力(包括它们的应用顺序)。像其它的FactoryBean实现一样,ProxyFactoryBean引入了一个间接层。如果你定义一个名为foo的ProxyFactoryBean, 引用foo的对象看到的将不是ProxyFactoryBean实例本身,而是一个ProxyFactoryBean实现里getObject() 方法所创建的对象。 这个方法将创建一个AOP代理,它包装了一个目标对象。

ProxyFactoryBean类本身也是一个JavaBean,其属性主要有如下用途:

  • 指定你希望代理的目标对象
  • 指定是否使用CGLIB。

一些主要属性从org.springframework.aop.framework.ProxyConfig里继承下来(这个类是Spring里所有AOP代理工厂的父类)。这些主要属性包括:

  • proxyTargetClass:这个属性为true时,目标类本身被代理而不是目标类的接口。如果这个属性值被设为true,CGLIB代理将被创建。
  • optimize:用来控制通过CGLIB创建的代理是否使用激进的优化策略。 除非完全了解AOP代理如何处理优化,否则不推荐用户使用这个设置。目前这个属性仅用于CGLIB代理; 对于JDK动态代理(缺省代理)无效。
  • frozen:如果一个代理配置是frozen的,就不允许对该配置进行修改。 这在简单优化和不希望调用者在代理创建后操作代理(通过Advised接口) 时很有用。缺省值为false,即可以进行类似添加附加通知的操作。
  • exposeProxy:决定当前代理是否被暴露在一个ThreadLocal 中以便被目标对象访问。如果目标对象需要获取代理而且exposeProxy属性被设为 true,目标对象可以使用AopContext.currentProxy()方法。
  • aopProxyFactory:使用AopProxyFactory的实现。这提供了一种方法来自定义是否使用动态代理,CGLIB或其它代理策略。 缺省实现将根据情况选择动态代理或者CGLIB。一般情况下应该没有使用这个属性的需要;它是被设计来在Spring 1.1中添加新的代理类型的。

ProxyFactoryBean中需要说明的其它属性包括:

  • proxyInterfaces:需要代理的接口名的字符串数组。 如果没有提供,将为目标类使用一个CGLIB代理。
  • interceptorNames:Advisor的字符串数组,可以包括拦截器或其它通知的名字。 顺序是很重要的,排在前面的将被优先服务。就是说列表里的第一个拦截器将能够第一个拦截调用。

这里的名字是当前工厂中bean的名字,包括父工厂中bean的名字。这里你不能使用bean的引用因为这会导致ProxyFactoryBean忽略通知的单例设置。
你可以把一个拦截器的名字加上一个星号作为后缀(*)。这将导致这个应用程序里所有名字以星号之前部分开头的通知器都被应用。

单例:工厂是否应该返回同一个对象,不论方法getObject()被调用的多频繁。 多个FactoryBean实现都提供了这个方法。缺省值是true。 如果你希望使用有状态的通知--例如,有状态的mixin--可以把单例属性的值设置为false来使用原型通知。

3.基于JDK和CGLIB的代理:

如果一个需要被代理的目标对象的类(后面将简单地称它为目标类)没有实现任何接口,那么一个基于CGLIB的代理将被创建。 这是最简单的场景,因为JDK代理是基于接口的,没有接口意味着没有使用JDK进行代理的可能.

如果ProxyFactoryBean的proxyTargetClass属性被设为true,那么一个基于CGLIB的代理将创建。 这样的规定是有意义的,遵循了最小惊讶法则(保证了设定的一致性)。甚至当ProxyFactoryBean的proxyInterfaces属性被设置为一个或者多个全限定接口名, 而proxyTargetClass属性被设置为true仍然将实际使用基于CGLIB的代理。

如果ProxyFactoryBean的proxyInterfaces属性被设置为一个或者多个全限定接口名,一个基于JDK的代理将被创建。 被创建的代理将实现所有在proxyInterfaces属性里被说明的接口; 如果目标类实现了全部在proxyInterfaces属性里说明的接口以及一些额外接口,返回的代理将只实现说明的接口而不会实现那些额外接口。

如果ProxyFactoryBean的proxyInterfaces属性没有被设置, 但是目标类实现了一个(或者更多)接口,那么ProxyFactoryBean将自动检测到这个目标类已经实现了至少一个接口, 一个基于JDK的代理将被创建。被实际代理的接口将是目标类所实现的全部接口; 实际上,这和在proxyInterfaces属性中列出目标类实现的每个接口的情况是一样的。 然而,这将显著地减少工作量以及输入错误的可能性。

 感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!


# Java  # AOP  # AOP详解  # AOP整理知识  # Java Spring AOP之PointCut案例详解  # Java aop面向切面编程(aspectJweaver)案例详解  # Java JDK动态代理(AOP)用法及实现原理详解  # Java动态代理和AOP应用示例  # Java JDK动态代理(AOP)的实现原理与使用详析  # java Spring AOP详解及简单实例  # 图解JAVA中Spring Aop作用  # Java之Spring AOP 实现用户权限验证  # Java SpringBoot整合SpringCloud  # 一篇文章教你将JAVA的RabbitMQz与SpringBoot整合  # Java SpringBoot启动指定profile的8种方式详解  # Java SpringBoot在RequestBody中高效的使用枚举参数原理案例详解  # Java SpringBoot实现AOP  # 多个  # 将被  # 如果你  # 设置为  # 抛出  # 设为  # 自定义  # 拦截器  # 这是  # 创建一个  # 你可以  # 第一个  # 实现了  # 可以使用  # 横切  # 或其它  # 来实现  # 这将  # 使用这个  # 点上 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: Laravel如何为API生成Swagger或OpenAPI文档  如何挑选优质建站一级代理提升网站排名?  个人网站制作流程图片大全,个人网站如何注销?  如何快速搭建高效WAP手机网站吸引移动用户?  Win10如何卸载预装Edge扩展_Win10卸载Edge扩展教程【方法】  C++用Dijkstra(迪杰斯特拉)算法求最短路径  Laravel如何配置中间件Middleware_Laravel自定义中间件拦截请求与权限校验【步骤】  今日头条AI怎样推荐抢票工具_今日头条AI抢票工具推荐算法与筛选【技巧】  Laravel API路由如何设计_Laravel构建RESTful API的路由最佳实践  PHP 实现电台节目表的智能时间匹配与今日/明日轮播逻辑  微信小程序 wx.uploadFile无法上传解决办法  Laravel怎么实现微信登录_Laravel Socialite第三方登录集成  如何用搬瓦工VPS快速搭建个人网站?  网站视频制作书签怎么做,ie浏览器怎么将网站固定在书签工具栏?  如何用AI帮你把自己的生活经历写成一个有趣的故事?  Laravel如何编写单元测试和功能测试?(PHPUnit示例)  Laravel Debugbar怎么安装_Laravel调试工具栏配置指南  ,交易猫的商品怎么发布到网站上去?  微信小程序 input输入框控件详解及实例(多种示例)  如何在VPS电脑上快速搭建网站?  laravel怎么使用数据库工厂(Factory)生成带有关联模型的数据_laravel Factory生成关联数据方法  Laravel如何使用Guzzle调用外部接口_Laravel发起HTTP请求与JSON数据解析【详解】  Laravel如何使用Service Provider注册服务_Laravel服务提供者配置与加载  JavaScript中如何操作剪贴板_ClipboardAPI怎么用  大型企业网站制作流程,做网站需要注册公司吗?  怎么用AI帮你设计一套个性化的手机App图标?  怎么制作一个起泡网,水泡粪全漏粪育肥舍冬季氨气超过25ppm,可以有哪些措施降低舍内氨气水平?  html5怎么画眼睛_HT5用Canvas或SVG画眼球瞳孔加JS控制动态【绘制】  大同网页,大同瑞慈医院官网?  Laravel如何使用.env文件管理环境变量?(最佳实践)  微信小程序 canvas开发实例及注意事项  如何有效防御Web建站篡改攻击?  Linux系统运维自动化项目教程_Ansible批量管理实战  Python面向对象测试方法_mock解析【教程】  Laravel如何清理系统缓存命令_Laravel清除路由配置及视图缓存的方法【总结】  Python正则表达式进阶教程_复杂匹配与分组替换解析  教学论文网站制作软件有哪些,写论文用什么软件 ?  Python图片处理进阶教程_Pillow滤镜与图像增强  如何快速生成高效建站系统源代码?  网站建设保证美观性,需要考虑的几点问题!  Laravel怎么配置.env环境变量_Laravel生产环境敏感数据保护与读取【方法】  如何在云服务器上快速搭建个人网站?  Laravel怎么创建自己的包(Package)_Laravel扩展包开发入门到发布  Laravel项目如何进行性能优化_Laravel应用性能分析与优化技巧大全  Chrome浏览器标签页分组怎么用_谷歌浏览器整理标签页技巧【效率】  Laravel如何实现全文搜索_Laravel Scout集成Algolia或Meilisearch教程  Laravel API资源(Resource)怎么用_格式化Laravel API响应的最佳实践  香港代理服务器配置指南:高匿IP选择、跨境加速与SEO优化技巧  Gemini怎么用新功能实时问答_Gemini实时问答使用【步骤】  如何用wdcp快速搭建高效网站?