360SDN.COM

Spring Framework 5 权威指南(31)

来源:程序员阮威  2017-09-11 13:16:52    评论:0点击:

这是一个Spring 5专题系列,其诞生的动机是:

1.介绍最新版本的Spring Framework;

2.介绍最系统化的Spring Framework;

3.介绍最佳实践的Spring Framework;

3.2 声明切入点

一个切入点声明由切入点签名和切入点表达式两部分组成。如下:

package org.xyz;

import org.aspectj.lang.annotation.Aspect;

 

@Aspect

public class NotVeryUsefulAspect{

 

    @Pointcut("execution(*transfer(..))") // the pointcutexpression

    private voidanyOldTransfer() {} // the pointcut signature

}

注意:作为切入点签名的方法返回类型只能是void

等价的基于schema风格的切入点声明如下:

<aop:config>

       <aop:aspect id="notVeryUsefulAspect" ref="notVeryUsefulAspect">

                <aop:pointcutid="anyOldTransfer"

                        expression="execution(*transfer(..))"/>

       </aop:aspect>

</aop:config>

也可以声明全局的切入点:

<aop:config>

       <aop:pointcut id="anyOldTransfer"

                        expression="execution(*transfer(..))"/>

</aop:config>

基于schema风格的方面中可以引用基于@AspectJ风格方面中定义的切入点:

<aop:config>

       <aop:pointcut id="notVeryUsefulAspect"

               expression="org.xyz.NotVeryUsefulAspect.anyOldTransfer()"/>

</aop:config>

切入点表达式可以使用&&||!(与、或和非)运算符进行组合:

@Pointcut("execution(public * *(..))")

private void anyPublicOperation() {}

 

@Pointcut("within(com.xyz.someapp.trading..*)")

private void inTrading() {}

 

@Pointcut("anyPublicOperation() && inTrading()")

private void tradingOperation() {}

当使用名字来引用切入点时,同样遵循Java的可见性规则(publicprotectedprivate),但不影响切入点匹配规则。

等价的基于schema风格的切入点声明如下:

<aop:config>

       <aop:pointcut id="businessService"

                        expression="execution(public **(..)) and within(com.xyz.someapp.trading..*)"/>

</aop:config>

注意:

1. 这种方式下可以使用andornot来代替&&||!运算符。

2.不同于切入点签名,这种方式定义的切入点id不能被引用。

切入点表达式中已经被Spring AOP支持的AspectJ切入点指示器(PCD)如下:

execution匹配方法执行连接点。

within限定匹配连接点,在指定类型中。

this限定匹配连接点,代理对象为指定类型。

target限定匹配连接点,目标对象为指定类型。

args限定匹配连接点,参数对象为指定类型。

@target限定匹配连接点,目标对象被标记为指定注解。

@args限定匹配连接点,参数对象被标记为指定注解。

@within限定匹配连接点,在标记为指定注解的类型中。

@annotation限定匹配连接点,主题被标记为指定注解。

注意:不同于AspectJSpring AOP是基于代理的AOP框架,因此thistarget分别指向代理对象和目标对象。

完整的AspectJ切入点语言中目前暂未被Spring支持的切入点指示器包括:callgetsetpreinitializationstaticinitializationinitializationhandleradviceexecutionwithincodecflowcflowbelowif@this@withincode

Spring AOP自己还支持一个额外的切入点指示器:

bean限定匹配连接点,在指定名称的Springbean(支持通配符)。形式如下:

bean(idOrNameOfBean)

这些指示器可以自然地分成三类:

kinded选择一个特定类型的连接点,例如:executiongetsetcallhandler

scoping选择一组感兴趣的连接点,例如:withinwithincode

contextual基于上下文的匹配,例如:thistarget@annotation

AspectJ在编译时对切入点进行处理以尝试优化匹配性能。但是,你可以通过进一步缩小匹配范围来提升性能。一个好的切入点应该至少包括前两个类型的指示器。只提供kindedcontextual类型的指示器也可以工作但是会影响织入性能。scoping类型的指示器是匹配速度比较快的,因为AspectJ可以很快的排除掉不需要处理的连接点,所以一个好的切入点应该总是包括一个scoping指示器。

一大波例子来袭:

任意public方法的执行:

execution(public * *(..))

 

任意名字以set开头的方法的执行:

execution(* set*(..))

 

任意定义在 AccountService接口中的方法的执行: 

execution(* com.xyz.service.AccountService.*(..))

 

任意定义在com.xyz.service包中的方法的执行:

execution(* com.xyz.service.*.*(..))

 

任意定义在com.xyz.service包及其子包中的方法的执行:

execution(* com.xyz.service..*.*(..))

 

com.xyz.service包中的任意连接点(Spring AOP只支持方法执行,下同)

within(com.xyz.service.*)

 

com.xyz.service包及其子包中的任意连接点:

within(com.xyz.service..*)

 

实现了 AccountService接口的代理中的任意连接点

this(com.xyz.service.AccountService)

 

实现了 AccountService接口的目标对象中的任意连接点:

target(com.xyz.service.AccountService)

 

运行时为Serializable类型的单个参数的任意连接点:

args(java.io.Serializable)

    注意:上面例子与execution(**(java.io.Serializable))的区别是,前者是运行时的实际类型,后者是声明时的类型。

标记了@Transactional注解的目标对象中的任意连接点:

@target(org.springframework.transaction.annotation.Transactional)

 

标记了@Transactional注解的对象中的任意连接点:

@within(org.springframework.transaction.annotation.Transactional)

 

标记了@Transactional注解的任意连接点:

@annotation(org.springframework.transaction.annotation.Transactional)

 

运行时被标记了@Classified注解的单个参数的任意连接点:

@args(com.xyz.security.Classified)

 

名称为tardeServiceSpring bean中的任意连接点:

bean(tradeService)

 

名称符合通配符Spring bean中的任意连接点:

bean(*Service)

建议定义一个全局的方面,来预先定义一些通用的切入点。例如:

package com.xyz.someapp;

 

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Pointcut;

 

@Aspect

public class SystemArchitecture{

 

       /**

         * A join point is in the web layer ifthe method is defined

         * in a type in the com.xyz.someapp.webpackage or any sub-package

         * under that.

         */

       @Pointcut("within(com.xyz.someapp.web..*)")

       public void inWebLayer() {}

 

       /**

         * A join point is in the service layerif the method is defined

         * in a type in thecom.xyz.someapp.service package or any sub-package

         * under that.

         */

       @Pointcut("within(com.xyz.someapp.service..*)")

       public void inServiceLayer() {}

 

       /**

         * A join point is in the data accesslayer if the method is defined

         * in a type in the com.xyz.someapp.daopackage or any sub-package

         * under that.

         */

       @Pointcut("within(com.xyz.someapp.dao..*)")

       public void inDataAccessLayer() {}

 

       /**

         * A business service is the executionof any method defined on a service

         * interface. This definition assumesthat interfaces are placed in the

         * "service" package, andthat implementation types are in sub-packages.

         *

         * If you group service interfaces byfunctional area (for example,

         * in packagescom.xyz.someapp.abc.service and com.xyz.someapp.def.service) then

         * the pointcut expression"execution(* com.xyz.someapp..service.*.*(..))"

         * could be used instead.

         *

         * Alternatively, you can write theexpression using the 'bean'

         * PCD, like so"bean(*Service)". (This assumes that you have

         * named your Spring service beans in aconsistent fashion.)

         */

       @Pointcut("execution(*com.xyz.someapp..service.*.*(..))")

       public void businessService() {}

 

       /**

         * A data access operation is theexecution of any method defined on a

         * dao interface. This definitionassumes that interfaces are placed in the

         * "dao" package, and thatimplementation types are in sub-packages.

         */

       @Pointcut("execution(*com.xyz.someapp.dao.*.*(..))")

       public void dataAccessOperation() {}

}

在任何需要切入点表达式的地方可以引用上面定义的切入点,例如:

<aop:config>

       <aop:advisor

                pointcut="com.xyz.someapp.SystemArchitecture.businessService()"

                advice-ref="tx-advice"/>

</aop:config>

 

<tx:advice id="tx-advice">

       <tx:attributes>

                <tx:methodname="*"propagation="REQUIRED"/>

       </tx:attributes>

</tx:advice>

阅读原文

为您推荐

友情链接 |九搜汽车网 |手机ok生活信息网|ok生活信息网|ok微生活
 Powered by www.360SDN.COM   京ICP备11022651号-4 © 2012-2016 版权