spring实战——4、面向切面的spring

前言:

AOP(Aspect-Oriented Programming):是面向方面编程或面向切面的简称;维基百科对其解释如下:

面向侧面的程序设计(aspect-oriented programming,AOP,又译作面向方面的程序设计、观点导向编程、剖面导向程序设计)是计算机科学中的一个术语,指一种程序设计范型。该范型以一种称为侧面(aspect,又译作方面)的语言构造为基础,侧面是一种新的模块化机制,用来描述分散在对象、类或函数中的横切关注点(crosscutting concern)。

侧面的概念源于对面向对象的程序设计的改进,但并不只限于此,它还可以用来改进传统的函数。与侧面相关的编程概念还包括元对象协议、主题(subject)、混入(mixin)和委托。

百度百科的解释如下:

在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率

总而言之,AOP的出现是为了简化程序设计,使得某个模块更加能够专注自己的核心代码工作,而不用操心一些普众化的工作(如spring中的事务、安全是贯穿于整个框架之中的,而不应该每个模块都去进行处理,否则的话代码就会变得冗余、耦合度高),降低应用各模块之间的耦合度。


4.1、什么是面向切面编程

4.1.1、AOP

aop的含义在前言部分已经介绍过了,现在我们来看看切面是怎么在应用中起作用的。


在上图1、2、3三个模块中,每个模块中都有相同的部分(a, b, c),重复编写这些相同的部分会造成应用效率低下、模块间耦合度高等等原因,现在通过使用AOP的编程思想,将这些相同的部分以切面的形式插入到1、2、3三个模块中去,这样可以使得a,b,c三个关注点几种到了一个地方(切面),而不是分散到多处代码中;并且服务模块(1,2,3)更加简洁,因为他们只包含其自身的核心关注点(核心代码的实现),其次要关注点(a,b,c)被转移到切面中去了。

现在我们来看一下AOP中的一些术语:

advice(通知):定义在连接点做什么,为切面增强提供织入接口。

poincut(切点):匹配通知所要织入的一个或多个连接点。

aspect(切面):通知+切点——通知定义了切面的“什么”和“何时”;切点定义了切面的“何处”。

连接点:程序中所有可以当成切点的点。

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

说明:我们来分析一下这些术语之间的关系;通知包含了需要用于应用对象的增强行为。连接点是程序执行过程中能够应用通知的所有点;切点定义了通知被应用的具体位置,定义了哪些连接点会得到通知。

4.1.2、spring对AOP的支持

spring提供了4中类型的AOP支持:

a、基于代理的经典spring AOP

b、纯POJO切面

c、@AspectJ注解驱动切面

d、注入式AspectJ切面

前三种都是由spring AOP实现的,第四种需要引入AspectJ(不是用Java编写的,是以Java语言扩展的方式实现的)来实现面向切面编程。

我们需要注意以下几点:

1、spring通知是Java编写的

2、spring在运行时通知对象:

spring通过在代理类中包裹切面,在运行期将切面织入到目标类形成代理类,代理类封装了目标类,并拦截被通知方法的调用,再把调用转发给真正的bean,在调用目标方法之前,由代理类执行切面的通知操作。

3、spring只支持方法级别的连接点

因为spring的AOP是基于动态代理实现的,所以spring无法支持属性、构造方法等连接点,因此spring无法像AspectJ那样创建更细粒度的通知。

4.2、通过切点来选择连接点

前面说过,切点的作用是用来准确定位应该在什么地方应用切面的通知。因此切点的编写应该指定切面所要作用在哪里。

spring支持的aspectj切点表达式:

arg() 限制连接点匹配参数为制定类型的执行方法。
@args() 限制连接点匹配参数由指定注解标注的执行方法。
execution() 用于匹配时连接点的执行方法。
this() 限制连接点匹配AOP代理的bean引用为指定类型的类。
target 限制连接点匹配目标对象为指定类型的类。
@target 限制连接点匹配特定的执行对象,这些对象对应的类要有指定类型的注解。
within() 限制连接点匹配指定的类型。
@within() 限制连接点匹配指定注解所标注的类型,当使用Spring AOP时,方法定义在由指定的注解所标注的类里。
@annotation 限制匹配带有指定注解的连接点。

编写切点:

另外spring提供了bean()指示器,它可以让我们在切点表达式中指定bean的id来标识bean。

4.3、使用注解创建切面

@Aspect注解标识某个类是切面。(切面类中使用)

@Pointcut定义切点的注解。(切面类中使用)

@EnableAspectJAutoProxy:启用aspectj自动代理(在Java配置类中启动自动代理功能)

<aop:aspectj-autoproxy>:在xml配置中启用自动代理。


如果我们需要处理的通知方法中的参数,那么我们需要在切点表达式中声明参数指示器,参数指示器中的参数跟通知方法中的参数一致,如下所示:



通过注解为bean引入新功能(方法)

像ruby、Python这些动态语言,有开放类的理念,他们可以不用直接修改对象或类的定义就能够为对象或类增加新的方法。但是,Java不是动态语言,一旦类编译完成了,我们就很难为该类添加新的功能了。不过我们可以通过代理的方式实现这个功能,但是实际上相当于是将当前bean和新的bean(包含新功能)合成一个bean,假装自己是原来的bean并实现了新功能。

在spring中使用@DeclareParents(value="concert.Performance+", defaultImpl=DefaultEncoreable.class)注解来实现该功能。该注解作用在要引入的接口上

value表示为哪种类型的bean引入此接口,defaultImpl表示为了引入该接口所实现的类。

4.4、在xml中声明切面

在使用xml声明切面中,每个元素的声明的含义与注解中关键字含义类似,这里不做过多赘述。

4.5、注入AspectJ切面

前面说过spring实现的aop功能有限,只能支持方法级别的连接点,但是在实际开发中我们所面临的场景可能不会这么简单,我们可能需要监控一个类的创建、属性修改,那么这时我们就需要使用AspectJ来实现AOP,spring提供了在spring中引入AspectJ切面这个功能。实现原理如下:

<bean class="AspectJ切面的路径"  factory-method="aspectOf">

    <property name="依赖bean名" ref="依赖bean" />

</bean>

通过AspectJ的aspectOf()工厂方法创建一个AspectJ切面,然后将其放入到spring容器中。然后就可以像<bean>元素规定的那样在该对象上进行依赖注入。

总结:

1、使用注解声明切面有一个明显的劣势,我们必须为通知类添加注解。为了做到这一点,我们必须有源码。

猜你喜欢

转载自blog.csdn.net/kangxidagege/article/details/80552789