Spring-AOP

面向切面编程(AOP)

1.横切关注点

在软件开发中,把散布在应用各处的功能称为横切关注点,比如日志、安全。
通常横切关注点是与我们的业务逻辑相互嵌套的,而AOP就是为了将横切关注点和业务逻辑分离。

2.切面

横切关注点可以模块化为特殊的类,这些类称为切面,它是通知和切点的结合。如下图所示:

切面取代了继承和委托,使用AOP,我们仍然在一个地方定义通用功能,但是可以通过声明的方式定义这个功能以何种方式在何处应用,而不修改受影响的类。

3.通知

在AOP术语中,切面的工作被称为通知,它定义了切面是什么以及何时使用。Spring切面定义了五种通知:

  • Before:在目标方法调用前执行通知
  • After:在目标方法调用后执行通知
  • After-returning:在目标方法成功执行后执行通知
  • After-throwing:在目标方法抛出异常时执行通知
  • Around:在目标方法调用前和调用后执行通知

4.连接点

连接点是应用执行过程中能够插入切面的一个点,其可能是调用方法时、抛出异常时、甚至修改一个字段时。

5.切点

切点定义了切面所通知的连接点的范围,即在何处应用切面。

6.织入

织入是把切面应用到目标对象并创建新的代理对象的过程。

7.动态代理

Spring AOP是在运行期将切面织入到Spring管理的bean中的,即Spring是基于动态代理的。
代理类包裹了切面,封装了目标类,并会拦截对目标类的方法调用。当代理拦截到方法调用时,先执行切面逻辑,之后把调用转发给真正的目标bean。
注意:基于JDK的动态代理只能代理实现了接口的类,基于cglib的采用继承的方式,两种类都可以代理。因为final类和静态方法是不能被代理的,所以aop也不能织入静态方法。

配置AOP

Spring框架集合了ProxyFactory和Cglib两种方式来实现AOP。Spring AOP能够根据上下文环境选择其一,一般而言,当业务对象实现了接口时会选择基于JDK的动态代理;当业务对象没有实现接口时会选择Cglib动态对目标对象进行子类化;如果实现了接口却发生异常,需开启@EnableAspectJAutoProxy(proxyTargetClass = true)强制使用Cglib。

1.在xml中配置

Spring的AOP配置元素能够以非侵入性的方式声明切面。
大多数的AOP配置元素必须 在<aop:config>元素的上下文内使用。使用<aop:aspect>元素中的ref属性可以声明一个简单的切面。部分配置元素如下:

  • <aop:after>
  • <aop:before>
  • <aop:around>
  • <aop:after-returning>
  • <aop:after-throwing>
  • <aop:aspect>定义一个切面
  • <aop:pointcut>定义一个切点

2.使用注解配置

  • 首先创建一个切面类,使用@Aspect注解此类声明为切面
  • 创建无参无方法体的方法作为切点ID,并使用@Pointcut("execution(* com.crab.service..(..))")注解的形式声明一个切点
  • 创建增强的方法体,添加如@Before("anyCut()")的注解,anyCut为上一步创建的切点

Spring AOP实战测试

在IOC的基础上需要的包如下:

1.使用xml配置

使用示例如下:

   <!-- 启用注解配置 -->
<!--    <aop:aspectj-autoproxy /> -->

    <!-- proxy-target-class属性默认为false,表示使用DynamicProxy实现AOP,设置为true表示使用Cglib实现AOP -->
   <aop:config proxy-target-class="true">
   
     <!-- 定义全局切点,后面使用id引入 -->
     <aop:pointcut id="anyCut" expression="execution(* com.crab.service.Tom.*(..))"/>
     
     <!-- 定义切面,ref指代理类的bean -->
     <aop:aspect ref="aspectDemo">
     
         <!-- 将切面织入切点,使用切面的method方法增强切点方法,在切点方法之前执行 -->
         <aop:before pointcut-ref="anyCut" method="divBefore" />
         
         <!-- 直接配置局部切点 -->
         <aop:after pointcut="execution(* com.crab.service.Tom.say(..))" method="divAfter" />
     </aop:aspect>
   </aop:config>

其中限制切点范围的execution中的内容分别表示:execution(类的返回类型+空格+类的方法的全限定名+(方法参数)),以*开始,表明了我们不关心方法返回值的类型。然后,我们指定了全限定类名和方法名。对于方法参数列表,我们使用两个点号(..)表明切点要选择任意的相应方法,无论该方法参数是什么。

2.使用注解配置

使用示例如下:

//声明此类为切面
@Aspect
//告知Spring为此类创建bean
@Component
public class AnnoAspect {

	//声明一个切入点,这里是service包里的所有方法,无参无方法体的方法名为切入点ID
	@Pointcut("execution(* com.crab.service.*.*(..))")
	private void anyCut() {} 
	
	@Pointcut("execution(* com.crab.service.Tom.say(..))")
	private void roundCut() {}
	
	@Before("anyCut()")
	public void divBef() {
		System.out.println("----------before-----------");
	}
	
	@Around("roundCut()")
	public void divAft() {
		System.out.println("----------round-----------");
	}
}

参考书籍

《Spring In Action》

posted @ 2018-10-11 20:55  bkycrab  阅读(144)  评论(0编辑  收藏  举报