Spring AOP、代理、基于代理类的AOP实现、AspectJ开发

1 AOP

1.1 AOP简介

  AOP(Aspect-Oriented Programming),即面向切面编程(也叫面向方面编程),是面向对象编程(OOP)的一种补充,是一种比较成熟的编程方式。

Spring AOP、代理、基于代理类的AOP实现、AspectJ开发
  在传统的业务处理代码中,通常都会进行事务处理、日志记录等操作。虽然使用OOP可以通过组合或者继承的方式来达到代码的重用,但如果要实现某个功能(如日志记录),同样的代码仍然会分散到各个方法中。这样,如果想要关闭某个功能,或者对其进行修改,就必须要修改所有的相关方法。不但增加了开发人员的工作量,而且提高了代码的出错率。

  为了解决这一问题,AOP思想随之产生。AOP采取横向抽取机制,将分散在各个方法中的重复代码提取出来,然后在程序编译或运行时,再将这些提取出来的代码应用到需要执行的地方。这种采用横向抽取机制的方式,采用传统的OOP思想显然是无法办到的,因为OOP只能实现父子关系的纵向的重用。虽然AOP是一种新的编程思想,但却不是OOP的替代品,它只是OOP的延伸和补充
  AOP的使用,可以实开发者专注于核心业务的实现,不必过多关注其他辅助业务逻辑的实现,提高了开发效率,增强了代码的可维护性。

1.2 AOP术语

  • 切面(Aspect):封装的用于横向插入系统功能(如事务、日志等)的类。
  • 连接点(Joinpoint):在程序执行过程中的某个阶段点。
  • 切入点(Pointcut):切面与程序的交叉点,即那些需要处理的连接点。
Spring AOP、代理、基于代理类的AOP实现、AspectJ开发
  • Advice(通知/增强处理):AOP框架在特定的切入点执行的增强处理,即在定义好的切入点处所要执行的程序代码。可以将其理解为切面类中的方法。
  • Target Object(目标对象):指所有被通知的对象,也被称为被增强对象。如果AOP框架采用的是动态的AOP实现,那么该对象就是一个被代理对象。
  • Proxy (代理) :将通知应用到目标对象之后,被动态创建的对象。
  • Weaving (织入) :将切面代码插入到目标对象上,从而生成代理对象的过程。

2 代理

2.1 静态代理

  以日志的写法为例,来体验静态代理。通常日志的写法:

Spring AOP、代理、基于代理类的AOP实现、AspectJ开发
  使用静态代理:
Spring AOP、代理、基于代理类的AOP实现、AspectJ开发
  被代理类HelloSpeaker继承IHello接口,只专注于自己的业务逻辑,没有关于日志输出的代码。代理类HelloProxy中的hello方法,在调用目标类方法前后都有日志输出,这很好体现了切面的思想。实际(ProxyDemo中)在调用hello方法时(`proxy.hello("Just")`),就等同于调用了目标类的hello方法。因为在ProxyDemo中new了一个HelloSpeaker,传到了HelloProxy当中。

2.2 动态代理

2.2.1 JDK动态代理

Spring AOP、代理、基于代理类的AOP实现、AspectJ开发

  两个方法:

  • invoke:是接口InvocationHandler中定义的方法,在Java中叫作回调。一旦LogHandler被调用时,就会主动调用invoke方法。
  • newProxy:主要作用是来创建proxy的,将我们的目标对象进行绑定,返回一个代理类。好处是可以代理任何东西,并没有限制在IHello接口上。

  实际调用时,newProxy创建代理对象,(iHello.hello("Just"))调用hello方法时,实际上调用了invoke方法。invoke中也是典型的面向切面的编程。
  JDK动态代理的实现需要一个接口和一个实现类,不是很灵活。

2.2.2 基于CGLIB实现动态代理

  CGLIB是可以直接对目标类进行动态代理。

Spring AOP、代理、基于代理类的AOP实现、AspectJ开发
  测试类中用到了Enhancer,来获取代理的对象。设置SuperClass(setSuperClass),即被代理类。然后setCallback,指的是回调的时候调用的方法。

3 基于代理类的AOP实现

3.1 Spring的通知类型

  Spring按照通知在目标类方法的连结点位置,可以分为5种类型:

Spring AOP、代理、基于代理类的AOP实现、AspectJ开发

3.2 ProxyFactoryBean

  ProxyFactoryBean是FactoryBean接口的实现类, FactoryBean负责实例化一个Bean ,而ProxyFactoryBean负责为其他Bean创建代理实例。在Spring中, 使用ProxyFactoryBean是创建AOP代理的基本方式。常用配置属性为:

Spring AOP、代理、基于代理类的AOP实现、AspectJ开发
使用如下:
Spring AOP、代理、基于代理类的AOP实现、AspectJ开发

4 AspectJ开发

4.1 概述

  AspectJ是一个基于Java语言的AOP框架,它提供了强大的AOP功能。Spring 2.0以后,Spring AOP引入了对AspectJ的支持,并允许直接使用AspectJ进行编程,而Spring自身的AOP API也尽量与AspectJ保持一致。新版本的Spring框架,也建议使用AspectJ来开发AOP。使用AspectJ实现AOP有两种方式:一种是基于XML的声明式AspectJ, 另一种是基于注解的声明式AspectJ。

4.2 两种声明式AspectJ

4.2.1 基于XML的声明式AspectJ

  通过XML方式来定义切面、切入点和通知,<aop:config>元素极其子元素:

Spring AOP、代理、基于代理类的AOP实现、AspectJ开发
实例:
Spring AOP、代理、基于代理类的AOP实现、AspectJ开发
  1. 配置切面
    配置切面使用<aop:aspect>元素,该元素会将一个已经定义好的Bean转换成切面Bean,所以配置文件中需要预先定义好一个普通的Spring Bean。配置时需要指定id和ref两个属性:id定义该切面的唯一标识名称;ref用于引用普通的Bean。

  2. 配置切入点
    <aop:pointcut>元素作为<aop:config>元素的子元素定义时,表示该切入点是全局切入点,它可被多个切面所共享;当<aop:pointcut> 元素作为<aop:aspect>元素的子元素时,表示该切入点只对当前切面有效。在定义<aop:pointcut>元素时,通常会指定id和expression两个属性:id用于指定切入点的唯一标识名称;expression用于指定切入点关联的切入点表达式。
    切入点表达式execution(* cn.edu.ujn.jdk.*.*(..)):意思是匹配cn.edu.ujn.jdk包中任意类的任意方法的执行。
    解释:第一个*代表返回类型为所有类型;cn.edu.ujn.jdk为需要拦截的包名;第二个*代表所有的类名;第三个*代表所有方法;括号中的两个..表示任意参数。
    切入点表达式基本格式:execution(modifiers-pattern? ret-type-pattern declaring-tyoe-pattern name-pattern(param-pattern) throws-pattern?)
    modifiers-pattern:定义的目标方法的访问修饰符,如public、private等。
    ret-type-pattern:定义目标方法的返回值类型,如void、String等。
    declaring-tyoe-pattern:定义目标方法的类路径,如cn.edu.ujn.jdk.UserDaoImpl
    name-pattern:具体需要被代理的目标方法,如add方法。
    param-pattern:需要被代理的目标方法包含的参数。
    throws-pattern:需要被代理的目标方法抛出的异常类型。
    注意:带有?的部分为可配置项,而其他部分属于必须配置项。

  3. 配置通知
    使用<aop:aspect>的子元素可以配置5种常用通知,这5个子元素不支持使用子元素,但在使用时可以指定一些属性其常用属性和描述如下:

Spring AOP、代理、基于代理类的AOP实现、AspectJ开发

4.2.2 基于注解的声明式AspectJ

  AspectJ框架为AOP的实现提供了一套注解,用以取代Spring配置文件中为实现AOP功能所配置的臃肿代码。AspectJ的注解及其描述如下所示:

Spring AOP、代理、基于代理类的AOP实现、AspectJ开发

声明:
若本人发布的作品涉及版权或存在其他问题,请联系我删除。
谢谢浏览!