面向切面编程(AOP)在提供模块化的意义上补充了 。但模块化的关键单元是切面而不是类。
AOP将程序逻辑分解为不同的部分(称为 )。它通过切点来增加模块化。
切点是能够影响整个应用程序的关注点,并且应该尽可能集中在代码中的一个位置,例如事务管理、身份验证、日志记录、安全性等
为什么使用AOP ?
它提供了可插入的方法,可以在实际逻辑之前,之后或周围动态添加其他关注点。假设一个类中有10个方法,如下所示:
有5种方法从m开始,2种从n开始,3种从p开始。了解场景,必须维护日志并在调用从m开始的方法后发送通知。如果没有AOP,我们可以从以m开头的方法调用方法(维护日志并发送通知)。在这种情况下,我们需要在所有5个方法中编写代码。
但是,如果客户说以后我不需要发送通知,你需要改变所有的方法。它导致了维护问题。AOP的解决方案我们不需要从方法中调用方法。现在,我们可以在类的方法中定义额外的关注点,比如维护日志、发送通知等。它的entry在xml文件中给出 ; 将来,如果客户机说要删除通知程序功能,我们只需要在xml文件中更改。因此,在AOP中维护很容易。
什么地方用 AOP ?
AOP主要用于以下情况:
提供声明式企业服务,如声明式事务管理。
它允许用户实现自定义方面。
AOP概念和术语
AOP概念和术语如下:
Join point
Advice
Pointcut
Introduction
Target Object
Aspect
Interceptor
AOP Proxy
Weaving
1)连接点(Joinpoint)
程序执行的某个特定位置:如类开始 、类初始化后、 某个方法调用前、调用后、方法抛出异常后。一个类或一段程序代码拥有一些具有边界性质的特定点,这些点中的特定点就称为“连接点”。Spring仅支持方法的连接点,即仅能在方法调用前、方法调用后、方法抛出异常时以及方法调用前后这些程序执行点织入增强。连接点由两个信息确定:第一是用方法表示的程序执行点;第二是用相对点表示的方位。
2)切点(Pointcut)
每个程序类都拥有多个连接点,如一个拥有两个方法的类,这两个方法都是连接点,即连接点是程序类中客观存在的事物。AOP通过“ ”定位特定的连接点。连接点相当于数据库中的记录,而切点相当于查询条件。切点和连接点不是一对一的关系,一个切点可以匹配多个连接点。在Spring中,切点通过 接口进行描述,它使用类和方法作为连接点的查询条件,Spring AOP的规则解析引擎负责切点所设定的查询条件,找到对应的连接点。其实确切地说,不能称之为查询连接点,因为连接点是方法执行前、执行后等包括方位信息的具体程序执行点,而切点只定位到某个方法上,所以如果希望定位到具体连接点上,还需要提供方位信息。
通知表示方面在特定连接点上采取的行动。有不同类型的通知:
Before Advice:它在连接点之前执行。
After Returning Advice:节点正常完成后执行。
After Throwing Advice:如果方法退出,则通过抛出异常来执行。
After (finally) Advice:连接点之后执行,而不管连接点退出是正常返回还是异常返回。
Around Advice:它在连接点之前和之后执行。
3)增强(Advice)
增强是织入到目标类连接点上的一段程序代码,在Spring中,增强除用于描述一段程序代码外,还拥有另一个和连接点相关的信息,这便是执行点的方位。结合执行点方位信息和切点信息,我们就可以找到特定的连接点。
4)目标对象(Target)
增强逻辑的织入目标类。如果没有AOP,目标业务类需要自己实现所有逻辑,而在AOP的帮助下,目标业务类只实现那些非横切逻辑的程序逻辑,而性能监视和事务管理等这些横切逻辑则可以使用AOP动态织入到特定的连接点上。
5)引介(Introduction)
引介是一种特殊的增强,它为类添加一些属性和方法。这样,即使一个业务类原本没有实现某个接口,通过AOP的引介功能,我们可以动态地为该业务类添加接口的实现逻辑,让业务类成为这个接口的实现类。
6)织入(Weaving)
织入是将增强添加对目标类具体连接点上的过程。AOP像一台织布机,将目标类、增强或引介通过AOP这台织布机天衣无缝地编织到一起。根据不同的实现技术,AOP有三种织入的方式:
a、编译期织入,这要求使用特殊的Java编译器。
b、类装载期织入,这要求使用特殊的类装载器。
c、动态代理织入,在运行期为目标类添加增强生成子类的方式。
Spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入。
7)代理(Proxy)
一个类被AOP织入增强后,就产出了一个结果类,它是融合了原类和增强逻辑的代理类。根据不同的代理方式,代理类既可能是和原类具有相同接口的类,也可能就是原类的子类,所以我们可以采用调用原类相同的方式调用代理类。
8)切面(Aspect)
切面由切点和增强(引介)组成,它既包括了横切逻辑的定义,也包括了连接点的定义,Spring AOP就是负责实施切面的框架,它将切面所定义的横切逻辑织入到切面所指定的连接点中。
Spring AOP的实现
Spring AOP实现由以下提供:
AspectJ
Spring AOP
JBoss AOP
Spring AOP
以下三种方法可以使用Spring AOP。但是广泛使用的方法是 注释样式。下面给出了使用spring AOP的三种方法:
由Spring1.2旧样式(基于dtd)(在Spring3中也支持)
由AspectJ注释风格
通过Spring XML配置样式(基于模式)
Spring AOP示例
以下是Spring1.2旧式AOP(基于dtd)实现的示例。虽然在Spring3也支持,但是advice将spring aop与aspectJ一起使用,
spring1.2旧式aop实现支持4种类型的advice。
Before Advice,在实际方法调用之前执行。
After Advice,在实际的方法调用之后执行。如果方法有返回值,则在返回值之后执行
Around Advice,在实际方法调用之前和之后执行。
Throws Advice,如果实际方法抛出异常,则执行 3在advice之后,它在实际方法调用之后执行。如果method返回一个值,则在返回值后执行。 在advice周围,它在实际方法调用之前和之后执行。 抛出advice如果实际方法抛出异常则执行它。
让我们通过下面给出的图表来理解advice 层次结构:
1)MethodBeforeAdvice示例
创建一个包含实际业务逻辑的类。
文件:A.java
现在,创建实现 接口的advisor类。
文件:BeforeAdvisor.java
在xml文件中,创建3个bean,一个用于A类,第二个用于 类,第三个用于 类。
文件:applicationContext.xml
ProxyFactoryBean类:
该ProxyFactoryBean的类是由Spring Famework提供。它包含2个属性target和 。A类的实例将被视为目标对象,而advisor类的实例将被视为拦截器。您需要将advisor对象作为列表对象传递,如上面给出的xml文件中所示。
类的编写如下:
文件:Test.java
Output:
在MethodBeforeAdvice中打印其他信息
我们可以打印其他信息,如方法名称, ,目标对象, ,代理类等。
您只需要更改两个类 和Test.java。
文件:BeforeAdvisor.java
File: Test.java
Output
2)AfterReturningAdvice 示例
创建一个包含实际业务逻辑的类。
文件:A.java 与前一个示例相同。
现在,创建实现 接口的advisor类。
文件:AfterAdvisor.java
File: Test.java Same as in the previous example.
Output
3)MethodInterceptor(AroundAdvice)示例
创建一个包含实际业务逻辑的类。
文件:A.java 与前一个示例相同。
现在,创建实现 接口的advisor类。
文件:AroundAdvisor.java
如上例所示创建xml文件,您只需在此处更改advisor 类。
文件:applicationContext.xml
文件:Test.java与前一个示例相同。
Output:
4) ThrowsAdvice 示例
File: Validator.java
File: ThrowsAdvisor.java
Create a class that contains actual business logic.
像前面的示例一样创建xml文件,您只需要更改Validator类和advisor类。
文件:applicationContext.xml
File: Test.java
Output
Spring AOP AspectJ注释示例
Spring框架advice您使用 实现,而不是Spring 1.2老式的基于dtd的AOP实现,因为它提供了更多的控制,而且易于使用。
有两种方法可以使用Spring AOP AspectJ实现:
通过注释。
通过xml配置(基于模式)
Spring AspectJ AOP实现提供了许多注释:
@Aspect将该类声明为aspect。
@Pointcut声明了切入点表达式。
用于创建advices 的注释如下:
@Before在调用实际方法之前应用它。
@After调用实际方法之后和返回结果之前应用。
@AfterReturning在调用实际方法之后和返回结果之前应用。但是你可以在advices中得到结果值。
@Around在调用实际方法之前和之后应用。
@AfterThrowing如果实际方法抛出异常,则应用它。
理解切入点理解切(入)点(Pointcut)
切入点是Spring AOP的一种表达语言。
注释用于定义切点。我们还可以通过名称引用切点表达式。以下为切入点表达式的简单示例。
切入点表达式的名称是doSomething()。无论返回类型如何,它都将应用于Operation类的所有方法。
理解切点表示式
让我们通过以下示例来理解切入点表达式:
它将适用于所有的 方法。
它将应用于Operation 的所有 方法
它将应用于Operation类的 方法。
它将应用于Employee 的所有 setter方法。
它将应用于 int值的Operation类的所有方法。
1)@Before示例
在实际业务逻辑方法之前应用。您可以在此处执行任何操作,例如conversion,authentication等。
创建一个包含实际业务逻辑的类。
文件:Operation.java
现在,创建包含在advice之前的aspect 类。
文件:TrackOperation.java
现在创建定义bean的 文件。
文件:applicationContext.xml
现在,让我们调用实际方法。
文件:Test.java
Output :
如果您更改如下所示的切点表达式:
Output :
可以看到,在调用k()方法之前没有打印内容。
2) @After Example
在调用实际的业务逻辑方法之后应用AspectJ通知。它可以用来维护日志、安全、通知等。
在这里,我们假设Operation.java, 和Test.java文件与@Before示例中给出的相同。
文件:TrackOperation.java
Output:
可以看到,在调用 、m()和 方法之后,会打印出额外concern ;
3) @AfterReturning Example
通过在返回advice后使用,我们可以在advice中得到结果。
创建包含业务逻辑的类。
文件:Operation.java
File: TrackOperation.java
File: applicationContext.xml
它与 示例中给出的相同
文件:Test.java
现在创建调用实际方法的测试类。
Output:
可以看到返回值打印了两次,一次是通过 类打印的,另一次是通过测试类打印的。
4) @Around 示例
在调用实际的业务逻辑方法之前和之后应用 通知 。
在这里,我们假设 文件与 示例中给出的相同。
创建一个包含实际业务逻辑的类。
文件:Operation.java
创建包含advise的aspect类。
您需要在advice方法中传递 引用,以便我们可以通过调用 方法来继续请求。
文件:TrackOperation.java
`` 文件:Test.java 现在创建调用实际方法的测试类。
Output :
5) @AfterThrowing 示例
通过使用after throw advice,我们可以在 n类中打印异常。让我们看看AspectJ在抛出advice之后的例子。
File: Operation.java
文件:applicationContext.xml 它与 示例中给出的相同
文件:Test.java 现在创建调用实际方法的Test类。
`Output :
```
Spring AOP AspectJ Xml配置示例
Spring允许您在xml文件中定义方面,建advices 和pointcuts 。
在上文中,我们已经看到了使用注释的aop示例。现在我们将通过xml配置文件看到相同的示例。
让我们看一下用于定义advice的xml元素。
aop:before在调用实际业务逻辑方法之前应用它之前。
aop:after在调用实际业务逻辑方法后应用它。
aop:after-returning在返回后,在调用实际的业务逻辑方法之后应用它。它可以用来拦截advice中的返回值。
aop:around它在调用实际业务逻辑方法之前和之后应用。
aop:after-throwing如果实际的业务逻辑方法抛出异常,则应用它。
1) aop:before 示例
AspectJ Before Advice在实际业务逻辑方法之前应用。您可以在此处执行任何操作,例如conversion,authentication 等。
创建一个包含实际业务逻辑的类。
文件:Operation.java
`现在,创建包含在advice之前的aspect 类。
文件:TrackOperation.java
`
File: applicationContext.xml
File: Test.java
Output:
可以看见 : 调用 ,m()和 方法之前会打印 。
2) aop:after 示例
我们假设Operation.java,TrackOperation.java和Test.java文件与aop中给出的相同: 。
现在创建定义bean的applicationContext.xml文件。
文件:applicationContext.xml
Output :
3) aop:after-returning 示例
通过使用 ,我们可以在advice中得到结果。
File: Operation.java
File: TrackOperation.java
`File: applicationContext.xml
File: Test.java
`Output:
`4) aop:around 示例
在调用实际业务逻辑方法之前和之后应用 。
创建一个包含实际业务逻辑的类。
文件:Operation.java
在advice方法中传递 引用,以便我们可以通过调用 方法来继续请求。
文件:TrackOperation.java
File: applicationContext.xml
File: Test.java
Output
5) aop:after-throwing 示例
通过使用 ,我们可以在 类中打印异常。让我们看看AspectJ在抛出advice之后的例子。
File: Operation.java
File: TrackOperation.java
`` File: applicationContext.xml
File: Test.java
Output :
END
领取专属 10元无门槛券
私享最新 技术干货