-
在软件开发中,散布在应用中多处的功能被称为横切关注点 cross-cutting concern,通常横切关注点(如日志)从概念上是与应用的业务逻辑相分离,却又嵌入在业务逻辑中。把横切关注点与业务逻辑相分离正是面向切面编程 AOP 所要解决的问题。
-
面向切面编程时,在一个地方定义通用功能,通过声明的方式定义这个功能以何种方式在何处应用,而无需修改被影响的类。横切关注点可以被模块化为特殊类,称为切面 aspect。
-
在 AOP 术语中,切面的工作被称为通知,定义了切面要完成的工作及何时执行。
-
Spring 切面支持 5 种类型的通知:前置通知 Before,后置通知 After,返回通知 After-Returning,异常通知 After-throwing,环绕通知 Around。
-
连接点是应用执行过程中能够插入切面的一个点,这个点可以是调用方法时、抛出异常时、甚至修改一个字段时。
-
切点是通知所要织入的一个或多个连接点。
-
切面是通知和切点的结合,通知和切点共同定义了切面的全部内容,何时在何处完成何种工作。
-
引入为向现有类添加新的方法或属性。
-
织入是把切面应用到目标对象并创建新的代理对象的过程,切面在指定的连接点(切点)被织入到目标对象中。
-
Spring 提供了 4 种类型的 AOP 支持:基于代理的经典 Spring AOP,纯 POJO 切面,@AspectJ 注解驱动的切面,注入式 AspectJ 切面。
-
借助 Spring 的 aop 命名空间可以将纯 POJO 转换为切面,遗憾的是这种方式只能通过 xml 配置。
-
注解驱动的 AOP 本质上依然是 Spring 基于代理的 AOP,编程模型几乎与 AspectJ 注解切面完全一致,好处在于可以不使用 xml 配置。
-
如果 AOP 需求超过了简单的方法调用,如构造器或属性拦截,可以使用 AspectJ 来实现切面。
-
在 Spring AOP 中使用 AspectJ 的切点表达式语言来定义切点。进一步了解 AspectJ 和 AspectJ 切点表达式语言,可以看 Ramniva Laddad 编写的《AspectJ in Action》。
-
切点表达式
execution (* package.class.function(..) && within(package.*))
。第一个*
表示任意返回类型,..
表示使用任意参数,&&
表示"与"关系,xml 中可以使用and
,类似||
可以使用or
,!
可以使用not
。 -
Spring 中引入了一个新的 bean 指示器,用来指定 bean 的 ID,如
execution (* package.class.function(..) && bean("beanID"))
限制切点只匹配特定的 bean,也可以在 bean()指示器前添加!
表示除特定 ID 以外的其他 bean。 -
@AspectJ
注解用来定义切面,在类的方法上使用定义通知的注解。AspectJ 提供了 5 个注解来定义通知:@After
,@AfterReturning
,@AfterThrowing
,@Around
,@Before
。定义通知的注解需要给定一个切点表达式作为它的值。 -
@PointCut
注解能够在一个@AspectJ
切面内定义可重用的切点。使用时在一个方法上添加注解,将切点表达式作为注解的值,方法为注解提供依附,方法名 function() 可在其他需要切点表达式的地方代替切点表达式。 -
在 JavaConfig 中,可以在配置类的级别上通过
@EnableAspectJAutoProxy
注解启动@AspectJ
的自动代理功能。xml 中使用<aop:aspectj-autoproxy />
。 -
环绕通知是最强大的通知类型,方法中需要有 ProceedingJoinPoint 参数(jp),并添加
@Around
注解。在方法体中,jp.proceed()
表示切点,可以围绕它编写各种通知。如果不调用 proceed(),通知实际上会阻塞被通知方法的调动。 -
对于有参数的通知,需要在切点表达式的方法中指定接受参数的类型,并通过
args(paramName)
限定符匹配参数名称。例如execution(* package.class.function(int) && args(paramName))
。 -
Java 不是动态语言,但是可以利用 AOP 中的"引入"概念,通过切面为 Spring bean 添加新方法。
-
面向注解的切面声明必须要为类添加注解,没有源码时,可通过 xml 配置声明。
-
大多数 aop 配置元素需要在
<aop:config>
元素的上下文内使用,<aop:aspect ref="beanId">
声明切面,<aop:pointcut id="pointId" expression="..." />
定义切点,<aop:before(其他通知类型) pointcut-ref="pointcutId" method="methodName" />
定义通知。 -
如果多个切面需要用到相同的切点,可以将
<aop pointcut>
元素放在<aop:config>
元素的范围内。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于