Spring学习教程之AOP模块的概述

概述

spirng-aop模块是Spring框架中的核心模块,虽然Spring Ioc container并不依赖AOP,但AOP给Ioc的实现提供了一种强大而灵活的解决方案。

在Spring Framework中,AOP主要是用于两种目的:

  • 提供一些 企业 级的声明式服务,典型的应用如 declarative transaction management .
  • 允许用户实现自己的aspects,用AOP的方式来帮助和补充OOP的功能及实现

AOP从功能的角度来讲,可能看作OOP编程方式的一种补充,提供了一种不同的代码或者系统组织方式。OOP中的核心概念是Class,而在AOP中则是Aspect。

spirng-aop模块是Spring框架中的核心模块,虽然Spring Ioc container并不依赖AOP,但AOP给Ioc的实现提供了一种强大而灵活的解决方案。

在Spring Framework中,AOP主要是用于两种目的:

  • 提供一些企业级的声明式服务,典型的应用如 declarative transaction management.
  • 允许用户实现自己的aspects,用AOP的方式来帮助和补充OOP的功能及实现

Spring AOP由纯Java实现,无须特殊的编译处理,也不需要控制类加载器的层次结构,所以它可以适用于Servlet Container和其它application server.

Spring AOP目前只支持方法级别的切换或拦截,属性的拦截现在不支持,如果想要拦截属性,可以考虑使用AspectJ语言。
Spring AOP的使用不同于其它大多数AOP框架。它的主要目的不是提供一套大而全的AOP实现,而是集成AOP不同实现协同Spring Ioc来帮助解决一些普遍性问题。

需要注意的是,一些细粒度的advised(如domain model),Spring AOP往往不能提供很好的支持,这场景也还是考虑AspectJ。即使如此,就普遍经验来说Spring AOP的强大机制依然能够解决大多数场景的问题。
那么该如何看待Spring AOP和AspectJ,引用Spring官方文档的原文:

Spring AOP will never strive to compete with AspectJ to provide a comprehensive AOP solution. We believe that both proxy-based frameworks like Spring AOP and full-blown frameworks such as AspectJ are valuable, and that they are complementary, rather than in competition. Spring seamlessly integrates Spring AOP and IoC with AspectJ, to enable all uses of AOP to be catered for within a consistent Spring-based application architecture. This integration does not affect the Spring AOP API or the AOP Alliance API: Spring AOP remains backward-compatible.

在Spring框架所有的模块设计中,始终遵守的核心信条之一是——无侵入性。

所以在使用Spring AOP时,不会强制我们在业务代码中引入特定类或者接口,可以最大限度的保持代码 clean and decouple。然而Spring也提供了另一种选择,如果有特定的场景需要的话,你可以在你的代码中直接引入Spring AOP。几乎所有Spring框架中的模块,在使用的方式上都会给你多种选择,以便让用户选择更适合自己场景的方式。使用AspectJ还是Spring AOP,使用annotation方式还是xml的配置方式,Depends On U。

了解了Spring AOP的初衷和使用场景,来看下它的大致实现原理

在软件世界中的绝大多数问题,都可以通过加一层来解决。

这里所说的层,当然是广义上的,可以是一层抽象,也可以是一层cache,大致含义是隔离和解耦的范畴。

在Spring的世界里,每一个模块的引入,或者第三方技术的集成,总会提供一个抽象层 ,对用户提供统一的API,屏蔽了所有的实现细节以及不同实现的差异。例如spring-cache,spring-jdbc,spring-jms以及spirng-messaging等模块都提供了一层抽象。

Spring AOP的实现是基于代理的机制,默认是采用Jdk dynamic proxy,也可以采用cglib的proxy。两者的区别主要是在于被代理的对象的不同。当目标对象是接口时,Jdk dynamic proxy可以完成代理,但目标对象是没有实现接口的类时(尽量少一些,面向接口编程是好习惯),是需要采用cglib proxy来完成代理的,当然你也可以强制接口也采用cglib来代理;另外需要注入或引用具体类型时,如果引用的东西恰恰是代理过的对象,此时也需要采用cglib的方式。

功能设计和实现上来可以分为两大块

  • aop基础设施的创建,可以看作是aopProxy的生成
  • aopProxy对象的调用时的处理拦截,即处理对目标对象的拦截器

AOP的创建

生成代理对象的核心类,ProxyFactoryBean getObjecct()

下图是生成代理时,是用Jdk还是cglib的选择逻辑:

找到了生成代理的具体执行者,那么这个操作是在什么时候被调用的呢,了解过Spring bean生命周期的都应该知道,bean在创建的时候,有一系列的回调接口供用户插入自定义的行为,来左右bean的一些特性,其中BeanPostProcessor是接口中的一种。以往的文章有介绍过(玩转Spring bean的终极利器)。而Spring AOP正是利用这个契机,在创建bean的过程中插了一手,如果正在创建的bean是我们aop的target,则创建代理,并最终把代理对象返回给Ioc。

AbstractAutoProxyCreator 这个类是一个BeanPostProcessor的实现,用来创建代理,来看这个处理器的后处理方法,最终是返回了createProxy()方法返回的代理

AOP切面的增强的执行

可以理解成对目标对象上所有拦截器链的调用

由于Spring AOP的代理具体实现有两种,JDK dynamic proxy和cglib,所以执行拦截器的方式有所不同,具体可以阅读源码JdkDynamicAopProxy类的invoke方法

对目标方法的调用最终是依靠ReflectiveMethodInvocation.

ReflectiveMethodInvocation中的proceed处理是采用递归的方式处理拦截器链

CglibAopProxy的 intercept方法

CglibMethodInvoation是继承了ReflectiveMethodInvocation,处理拦截器链也是用的上边的proceed()方法。

在使用Spring AOP时需要注意的两点细节:

1、在类内部的方法调用时(self-invoke),Spring AOP不起作用,原因是内部调用没通过代理对象,直接使用的目标对象。解决方法有:

  • 重构代码,避免内部调用
  • AopContext.currentProxy()
  • 或者干脆使用AspectJ语言吧...

2、在注入bean时,如果想注入bean的具体的类型而不是接口,那么采用cglib吧

Spring AOP的功能很强大,设计巧妙,这里梳理了主要脉络,细节不再一一讨论。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • 详解SpringBoot AOP 拦截器(Aspect注解方式)

    常用用于实现拦截的有:Filter.HandlerInterceptor.MethodInterceptor 第一种Filter属于Servlet提供的,后两者是spring提供的,HandlerInterceptor属于Spring MVC项目提供的,用来拦截请求,在MethodInterceptor之前执行. 实现一个HandlerInterceptor可以实现接口HandlerInterceptor,也可以继承HandlerInterceptorAdapter类,两种方法一样.这个不在本文

  • 深入浅析Spring 的aop实现原理

    什么是AOP AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善.OOP引入封装.继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合.当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力.也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系.例如日志功能.日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无

  • java基于spring注解AOP的异常处理的方法

    一.前言 项目刚刚开发的时候,并没有做好充足的准备.开发到一定程度的时候才会想到还有一些问题没有解决.就比如今天我要说的一个问题:异常的处理.写程序的时候一般都会通过try...catch...finally对异常进行处理,但是我们真的能在写程序的时候处理掉所有可能发生的异常吗? 以及发生异常的时候执行什么逻辑,返回什么提示信息,跳转到什么页面,这些都是要考虑到的. 二.基于@ControllerAdvice(加强的控制器)的异常处理 @ControllerAdvice注解内部使用@Except

  • 利用spring AOP记录用户操作日志的方法示例

    前言 最近项目已经开发完成,但发现需要加用户操作日志,如果返回去加也不太现实,所以使用springAOP来完成比较合适.下面来一起看看详细的介绍: 注解工具类: @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface LogAnnotation { String operateModelNm() default ""; String operateFuncNm() default

  • spring基础概念AOP与动态代理理解

    一.代理模式 代理模式的英文叫做Proxy或Surrogate,中文都可译为"代理",所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动.在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 以简单模拟事务的执行过程说明各种代理区别 1.1 静态代理 由程序员创建或由特定工具自动生成源代码,再对其编译.在程序运行前,代理类的.class文件就已经存在了. public interface PersonDao { vo

  • 详解spring面向切面aop拦截器

    spring中有很多概念和名词,其中有一些名字不同,但是从功能上来看总感觉是那么的相似,比如过滤器.拦截器.aop等. 过滤器filter.spring mvc拦截器Interceptor .面向切面编程aop,实际上都具有一定的拦截作用,都是拦截住某一个面,然后进行一定的处理. 在这里主要想着手的是aop,至于他们的比较,我想等三个都一一了解完了再说,因此这里便不做过多的比较. 在我目前的项目实践中,只在一个地方手动显示的使用了aop,那便是日志管理中对部分重要操作的记录. 据我目前所知,ao

  • Spring AOP的几种实现方式总结

    AOP核心概念 1.横切关注点 对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点 2.切面(aspect) 类是对物体特征的抽象,切面就是对横切关注点的抽象 3.连接点(joinpoint) 被拦截到的点,因为spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器 4.切入点(pointcut) 对连接点进行拦截的定义 5.通知(advice) 所谓通知指的就是指拦截到连接点之后要执行的代码,通知分为前置.后置.异常

  • 利用Spring AOP记录方法的执行时间

    一.前言 对于spring aop这个我就不多介绍了,网上一搜一大把,使用过spring的人都知道spring的ioc和aop.ioc我们常用,但在我们自己的系统中,aop的使用几乎为零,除了这个监控的小功能应用到了,其他的基本上没有使用到.下面小编就给大家整理下利用Spring AOP记录方法执行时间的解决方案,有需要的一起看看吧. 二.解决方案 1.传统方法 最简单.粗暴的方法是给各个需要统计的方法开始和结尾处加的时间戳,然后差值计算结果即可,代码如下: long startTime = S

  • 实例讲解Java的Spring框架中的AOP实现

    简介 面向切面编程(AOP)提供另外一种角度来思考程序结构,通过这种方式弥补了面向对象编程(OOP)的不足. 除了类(classes)以外,AOP提供了 切面.切面对关注点进行模块化,例如横切多个类型和对象的事务管理. (这些关注点术语通常称作 横切(crosscutting) 关注点.) Spring的一个关键的组件就是 AOP框架. 尽管如此,Spring IoC容器并不依赖于AOP,这意味着你可以自由选择是否使用AOP,AOP提供强大的中间件解决方案,这使得Spring IoC容器更加完善

  • spring aop两种配置方式

    第一种:注解配置AOP 注解配置AOP(使用 AspectJ 类库实现的),大致分为三步: 1. 使用注解@Aspect来定义一个切面,在切面中定义切入点(@Pointcut),通知类型(@Before, @AfterReturning,@After,@AfterThrowing,@Around). 2. 开发需要被拦截的类. 3. 将切面配置到xml中,当然,我们也可以使用自动扫描Bean的方式.这样的话,那就交由Spring AoP容器管理. 另外需要引用 aspectJ 的 jar 包:

随机推荐