目录 start

  1. AOP
    1. 动态代理
    2. 基本概念
    3. 基本配置
    4. 注意
      1. 1 Spring AOP还是完全用AspectJ?
      2. 2 Spring AOP中使用@AspectJ还是XML?
      3. 3 混合切面类型

目录 end|2019-10-19 17:04|


AOP

Aspect Oriented Programming 面向切面编程

动态代理

这是AOP的起源, 最初是JDK的动态Proxy -> cglib/asm

笔记: 代理

基本概念

英文 解释
JoinPoint 切入面、连接点、切入点(所有方法)
PointCut 切点(特殊的连接点,需要增强的连接点)
Advice 增强(切入点的逻辑,待添加的功能)
Aspect 切面(切点和增强的合集)
Target 目标对象(被增强的实例)
Weave 织入(增强切点的过程)
Proxy 代理(增强后的类,一般是使用了代理类) 装饰器模式
Introduction 引介(为类添加属性和方法) 用的较少因为破坏了OOP思想

基本配置

XML文件头

1
2
3
4
5
6
7
8
9
10
11
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
</beans>

  • 方法级别的添加代理,Servlet中的过滤器也类似(但是那个是类级别的)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- 基本类 提供切点 -->
<bean id="student" class="cn.spring.aop.Student"></bean>
<!-- 增强部分 -->
<bean id="adder" class="cn.spring.aop.NewDeal"></bean>
<!-- 使用aop的自动提示也要配置上面的头文件声明 -->
<aop:config>
<!--aspect表示切面 ref 标明增强方法的类来源 -->
<aop:aspect id="myAop" ref="adder">
<!-- execution 是表达式(正则一样的功能)匹配的是具体的切点 -->
<aop:pointcut expression="execution(* cn.spring.aop.Student.run(..))" id="needAdd"/>
<!-- 织入 的过程 将增强和切入点结合 -->
<aop:before method="add" pointcut-ref="needAdd"/>
<aop:after method="af" pointcut-ref="needAdd"/>
<aop:around method="around" pointcut-ref="needAdd"/>
</aop:aspect>
</aop:config>

注意

  • 要注意环绕的写法 public void around(ProceedingJoinPoint m)throws Throwable{

  • 然后在test类中直接getBean(基类)但是实际上是获取到的是装饰好的代理对象

  • 善用debug 调试看是否获取到的是代理对象 $proxy

  • 在Spring的配置文件中,所有的切面和通知器都必须定义在<aop:config> 元素内部。 一个application context可以包含多个 <aop:config>。 一个<aop:config> 可以包含 pointcutadvisoraspect 元素(注意它们必须按照这样的顺序进行声明)。

1 Spring AOP还是完全用AspectJ?

做能起作用的最简单的事。Spring AOP比完全使用AspectJ更加简单,因为它不需要引入AspectJ的编译器/织入器到你开发和构建过程中。
如果你仅仅需要在Spring bean上通知执行操作,那么Spring AOP是合适的选择。如果你需要通知domain对象或其它没有在Spring容器中
管理的任意对象,那么你需要使用AspectJ。如果你想通知除了简单的方法执行之外的连接点(如:调用连接点、字段get或set的连接点等等),
也需要使用AspectJ。
当使用AspectJ时,你可以选择使用AspectJ语言(也称为“代码风格”)或@AspectJ注解风格。
如果切面在你的设计中扮演一个很大的角色,并且你能在Eclipse中使用AspectJ Development Tools (AJDT), 那么首选AspectJ语言 :-
因为该语言专门被设计用来编写切面,所以会更清晰、更简单。如果你没有使用
Eclipse,或者在你的应用中只有很少的切面并没有作为一个主要的角色,你或许应该考虑使用@AspectJ风格
并在你的IDE中附加一个普通的Java编辑器,并且在你的构建脚本中增加切面织入(链接)的段落。

2 Spring AOP中使用@AspectJ还是XML?

如果你选择使用Spring AOP,那么你可以选择@AspectJ或者XML风格。总的来说,如果你使用Java 5, 我们建议使用@AspectJ风格。
显然如果你不是运行在Java 5上,XML风格是最佳选择。XML和@AspectJ 之间权衡的细节将在下面进行讨论。
XML风格对现有的Spring用户来说更加习惯。它可以使用在任何Java级别中(参考连接点表达式内部的命名连接点,虽然它也需要Java 5)
并且通过纯粹的POJO来支持。当使用AOP作为工具来配置企业服务时(一个好的例子是当你认为连接点表达式是你的配置中的一部分时,
你可能想单独更改它)XML会是一个很好的选择。对于XML风格,从你的配置中可以清晰的表明在系统中存在那些切面。
XML风格有两个缺点。第一是它不能完全将需求实现的地方封装到一个位置。DRY原则中说系统中的每一项知识都必须具有单一、无歧义、权威的表示。
当使用XML风格时,如何实现一个需求的知识被分割到支撑类的声明中以及XML配置文件中。当使用@AspectJ风格时就只有一个单独的模块 -切面-
信息被封装了起来。 第二是XML风格同@AspectJ风格所能表达的内容相比有更多的限制:仅仅支持”singleton”切面实例模型,并且不能在XML中组合命名连接点的声
明。 例如,在@AspectJ风格中我们可以编写如下的内容:

1
2
3
4
5
6
@Pointcut(execution(* get*())) 
public void propertyAccess() {}
@Pointcut(execution(org.xyz.Account+ *(..))
public void operationReturningAnAccount() {}
@Pointcut(propertyAccess() && operationReturningAnAccount())
public void accountPropertyAccess() {}

在XML风格中能声明开头的两个连接点:

1
2
<aop:pointcut id="propertyAccess" expression="execution(* get*())"/> 
<aop:pointcut id="operationReturningAnAccount" expression="execution(org.xyz.Account+ *(..))"/>

但是不能通过组合这些来定义accountPropertyAccess连接点

  • @AspectJ风格支持其它的实例模型以及更丰富的连接点组合。它具有将将切面保持为一个模块单元的优点。 还有一个优点就是@AspectJ切面能被Spring AOP和AspectJ两者都理解
  • 所以如果稍后你认为你需要AspectJ 的能力去实现附加的需求,那么你非常容易转移到基于AspectJ的途径。总而言之,我们更喜欢@AspectJ风格只要你有切面 去做超出简单的“配置”企业服务之外的事情。

3 混合切面类型

我们完全可以混合使用以下几种风格的切面定义:使用自动代理的@AspectJ 风格的切面,schema-defined <aop:aspect> 的切面,
和用 <aop:advisor> 声明的advisor,甚至是使用Spring 1.2风格的代理和拦截器。
由于以上几种风格的切面定义的都使用了相同的底层机制,因此可以很好的共存。