spring学习之---spring的AOP

来源:互联网 发布:淘宝宜家代购是真的吗 编辑:程序博客网 时间:2024/06/06 09:40

AOP是面向切面编程。AOP和OOP互为补充,面向对象编程将程序分解成各个层次的对象,而面向切面编程将程序运行过程分解成各个切面。面向对象编程是从静态角度考虑程序结构,而面向切面编程则是从动态角度考虑程序运行过程。

1.AOP的基本概念

AOP从程序运行角度考虑程序的流程,提取业务处理过程的切面。AOP面向的是程序运行中各个步骤,希望以更好的方式来组合业务处理的各个步骤。
AOP框架不与特定的代码耦合,AOP框架能处理程序执行中特定的切入点,而不与某个具体类耦合。
面向切面编程的一些术语:

  • 切面(Aspect):切面用于组织多个Advice,Advice放在切面中定义。
  • 连接点(Joinpoint):程序执行过程中明确的点,如方法的调用,或者异常的抛出。在Spring AOP中,连接点总是方法的调用。
  • 增强处理(Advice):AOP框架在特定的切入点执行的增强处理。
  • 切入点(Pointcut):可以插入增强处理的连接点。当某个连接点满足指定要求时,该连接点将被添加增强处理,该连接点也就变成了切入点。
  • 引入:将方法或字段添加到被处理的类中。spring允许将新的接口引入到任何被处理的对象中。
  • 目标对象:被AOP框架进行增强处理的对象,也被称为被增强的对象。如果AOP框架采用的是动态AOP实现,那么该独享就是一个被代理的对象。
  • AOP代理:AOP框架创建的对象,代理就是对目标对象的加强。实现接口的目标对象的代理是JDK动态代理,不实现接口的目标对象的代理为cglib代理。
  • 织入(Weaving):将增强处理添加到目标对象中,并创建一个被增强的对象(AOP代理)的过程就是织入。织入有两种实现方式—编译时增强(如AspectJ)和运行时增强(如Spring AOP)。

2.spring的AOP支持

spring中的AOP代理由spring的IoC容器负责生成、管理、其依赖关系也由IoC容器负责管理。因此,AOP代理可以直接使用容器中的其他Bean实例作为目标,这种关系可由IoC容器的依赖注入提供。spring默认使用Java动态代理来创建AOP代理,这样就可以为任何接口实例创建代理了。
spring目前仅支持将方法调用作为连接点(Jointpoint),如果需要把对成员变量的访问和更新也作为增强处理的连接点,则可以考虑使用AspectJ。
AOP编程需要如下三个部分:

  • 定义普通业务组件。
  • 定义切入点,一个切入点可能横切多个业务组件。
  • 定义增强处理,增强处理就是在AOP框架为普通业务组件织入的处理动作。
    一旦定义了合适的切入点和增强处理,AOP框架将会自动生成AOP代理。

3.基于注解的”零配置”方式

为了启用spring对@AspectJ切面配置的支持,并保证spring容器中的目标Bean被一个或多个切面自动增强,必须在配置文件中配置如下:

    <beans>        <aop:aspectj-autoproxy/>    </beans>

为了在spring应用中启用@AspectJ支持,还需要在应用的类加载路径下增加:aspectjweaver.jar、aspectjrt.jar、aopalliance.jar。

(1)定义切面Bean

    @Aspect    public class LogAspect{    }

使用@Aspect标注一个Java类,该Java类将会作为切面Bean,spring不会把该Bean当成组件Bean处理,因此负责自动增强的后处理Bean将会略过该Bean,不会对该Bean进行任何增强处理。

(2)定义Before增强处理

    @Aspect    public class AuthAspect{        @Before("execution(* com.hyq.impl.*.*(..))")        public void authority(){            System.out.println("...");        }    }

使用Before增强处理只能在目标方法执行之织入增强,如果Before处理需要阻止目标方法的执行,可通过抛出一个异常来实现。
在spring配置文件中配置自动搜索Bean组件、自动搜索切面类。spring AOP自动对Bean组件进行增强。

    <context:component-scan base-package="">        <context:include-filter type="annotation"            expression="org.aspectJ.lang.annotation.Aspect"/>    </context:component-scan>

(3)定义AfterReturning增强处理
AfterReturning增强处理将在目标方法正常完成后被织入。
使用@AfterReturning注解可指定如下两个常用属性:

  • pointcut:指定该切入点对应的切入表达式。
  • returning:该属性值指定一个形参名,用于表示Adive方法中可定义于此同名的形参,该形参可用于访问目标方法的返回值。
    @Aspect    public class LogAspect{        @AfterReturning(returning="rvt",pointcut="exxcution(* com.hyq.impl.*.*(..))")        public void log(Object rvt){            System.out.println("...");        }    }

@AfterReturning注解的returning属性所指定的形参名必须对应于增强处理中的一个形参名,当目标方法执行返回后,返回值作为相应的参数值传入增强处理方法。

(4)定义AfterThrowing增强处理
AfterThrowing增强处理主要用于处理程序中未处理的异常。
使用@AfterThrowing注解时可指定如下两个常用属性:

  • pointcut:用于指定该切入点对应的切入表达式。
  • throwing:该属性值指定一个形参名,用于表示Advice方法中定义于此同名的形参,该形参可用于访问目标方法抛出的异常。

@AfterThrowing注解的throwing属性中指定的参数名必须与增强处理方法内的一个形参对应。当目标方法抛出一个未处理的异常时,该异常将会传给增强处理方法对应的参数。

catch捕捉意味着完全处理该异常,如果catch块中没有重新抛出新异常,则该方法可以正常结束;而AferThrowing处理虽然处理了该异常,但它不能完全处理该异常,该异常依然会传播到上一级调用者(本示例程序中直接传播到JVM,故导致程序终止)。

(5)After增强处理
AferReturning增强处理只有在目标方法成功完成后才会被织入。
After增强处理不管目标方法如何结束,它都会被织入。
After增强处理的作用非常类似于异常处理中finally块的作用—无论如何,它总会在方法执行结束之后被织入,因此特别适用于进行资源回收。

(6)Around增强处理
Around增强处理既可在执行目标方法之前织入增强动作,也可在执行目标方法之后织入增强动作。
Around增强处理可以改变执行目标方法的参数值,也可以改变执行目标方法之后的返回值。
当定义一个Around增强处理方法时,该方法的第一个形参必须是ProceedingJoinPoint类型(至少包含一个形参),在增强处理方法体内,调用ProceedingJoinPoint参数的proceed()方法才会执行目标方法。
调用ProceedingJoinPoint参数的proceed()方法时,还可以传入一个Object[]对象作为参数,该数组中的值将被传入目标方法作为执行方法的实参。

(7)访问目标方法的参数
访问目标方法最简单的做法是定义增强处理方法时将第一个参数定义成JoinPoint类型,JoinPoint里包含了如下几个常用的方法:

  • Object[] getArgs():返回执行目标方法时的参数。
  • Signature getSignature():返回被增强的方法的相关信息。
  • Object getTarget():返回被织入增强处理的目标对象。
  • Object getThis():返回AOP框架为目标对象生成的代理对象。

ProceedingJoinPoint类型时JoinPoint类型的子类。

如果应用需要指定不用切面类里增强助力的优先级,spring提供了如下两种解决方案:

  • 让切面类实现org.springframework.core.Ordered接口,实现该接口只需要实现一个int getOrder()方法,该方法的返回值越小,则优先级越高。
  • 直接使用@Order注解来修饰一个切面类,使用@Order注解时可指定一个int型的value属性,该属性值越小,则优先级越高。

访问目标方法的参数的另一种方式:

    @Aspect    public class AccessAspect{        @AfterReturning(returning="rvt" pointcut="execution("* com.hyq.impl.*.*(..)) && args(arg0,arg1)")        public void access(Object rvt,String arg0,String arg1){            System.out.println("调用目标方法第一个参数为:" + arg0);            System.out.println("调用目标方法第二个参数为:" + arg1);        }    }

(8)定义切入点
定义切入点,其实质就是为一个切入点表达式起一个名称,从而允许在多个增强处理中重用该名称。
切入点表达式用于指定该切入点和哪些方法进行匹配,包含名字和任意参数的方法签名将作为该切入点的名称。
在@AspectJ风格的AOP中,切入点签名采用一个普通的方法定义(方法体通常为空)来提供,且该方法的返回值必须为void;切入点表达式需要使用@Pointcut注解来标注。

    @PointCut("execution(* com.hyq.impl.*.*(..)")    private void myPointcut(){    }    @After(pointcut="myPointcut()",returning="retVal")    public void writeLog(Object retVal){    }

(9)切入点指示符

  • execution:用于匹配执行方法的连接点。
  • within:用于限定匹配特定类型的连接点。
  • this:用于限定AOP代理必须是指定类型的实例,匹配该对象的所有连接点。
  • target:用于限定目标对象必须是指定类型的实例,匹配该对象的所有连接点。
  • args:用于对连接点的参数类型进行限制,要求参数类型时指定类型的实例。

(10)组合切入点表达式

  • &&:要求连接点同时匹配两个切入点表达式。
  • ||:只要连接点匹配任意一个切入点表达式。
  • !:要求连接点不匹配指定的切入点表达式。

4.基于XML配置文件的管理方式

aop:命名空间来定义切面、切入点和增强处理。
在spring配置文件中,所有的切面、切入点和增强处理都必须定义在<aop:config.../>元素内部,该元素可以包含pointcut、advisor和aspect元素,且这三个元素必须按照此顺序来定义。

(1)配置切面
<aop:aspect.../>元素来定义切面,其实质是将一个已有的spring Bean转换成切面Bean,所有需要先定义一个普通的spring Bean。
如下三个属性:

  • id:定义该切面的标识符。
  • ref:用于将ref属性所引用的普通Bean转换成切面Bean。
  • order:指定该切面Bean的优先级。

(2)配置增强处理

  • <aop:before.../>
  • <aop:after.../>
  • <aop:after-returning.../>
  • <aop:after-throwing.../>
  • <aop:around.../>

通常可指定如下属性:

  • pointcut:指定一个切入点表达式。
  • pointcut-ref:指定一个已经存在的切入点名称。
  • method:该属性指定一个方法名,指定将切面Bean的该方法转换为增强处理。
  • throwing:用于指定一个形参名,通过该形参访问目标方法所抛出的异常。
  • returning:用于指定一个形参名,通过该形参访问目标方法的返回值。

(3)配置切入点
<aop:pointcut.../>元素来定义切入点,既可配置全局切入点,也可配置仅对该切面有效的切入点。

  • id:指定该切入点的标识名。
  • expression:指定该切入点关联的切入点表达式。
原创粉丝点击