0%

Spring中AspectJ的XML开发

  • schema-defined aspects只支持singleton model,即:所有基于配置文件的切面只支持单例模式
  • Spring所有的切面和通知器都必须放在一个<aop:config>内(可以配置包含多个<aop:config>元素),每一个<aop:config>可以包含pointcutadvisoraspect元素(必须按照以上顺序进行声明)
  • <aop:config>风格的配置大量使用了Spring的自动代理机制

切面(Aspect)

1
2
3
4
5
6
7
8
9
10
11
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean class="aop.schema.MyAspect" id="myAspect"/>
<bean class="aop.schema.MyBiz" id="myBiz"/>
<aop:config>
<aop:aspect ref="myAspect" id="myAspectAOP">
···
</aop:aspect>
</aop:config>
</beans>

切入点(Pointcut)

首先,介绍这里使用的一些基本通配符的含义

  • * : 匹配任意数量的字符

  • + :匹配制定数量的类及其子类

  • .. :匹配本包

  • … :匹配本包及其子包


  • execution(权限类型)
  • execution(public* *(..))
                                                    切入点为执行所有public方法时
  • execution(* set*(..))
                                                    切入点为执行所有set开始的方法时
  • execution(* com.xyz.service.AccountService.*(..))
                                                    切入点为执行AccountService类中的所有方法时
  • execution(* com.xyz.service..(..))
                                                    切入点为执行com.xyz.service包下的所有方法时
  • execution(* com.xyz.service…(..))
                                                    切入点为执行com.xyz.service包及其子包下的所有方法时

以下,Only in Spring AOP

  • within(com.xyz.service.*)
  • within(com.xyz.service..*)
                                                    within 用于匹配指定类型内的方法执行
  • this(com.xyz.service.AccountService)
                                                    this 用于匹配当前AOP代理对象类型的执行方法
  • target(com.xyz.service.AccountService)
                                                    target用于匹配当前目标对象类型的执行方法
  • args(java.io.Serializable)
                                                    args用于匹配当前执行的方法传入的参数为指定类型的执行方法
  • @target(org.springframework.transaction.annotation.Transactional)
  • @within(org.springframework.transaction.annotation.Transactional)
  • @annotation(org.springframework.transaction.annotation.Transactional)
  • @args(com.xyz.security.Classified)
  • bean(tradeService)
  • bean(*Service)
1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean class="aop.schema.MyAspect" id="myAspect"/>
<bean class="aop.schema.MyBiz" id="myBiz"/>
<aop:config>
<aop:aspect ref="myAspect" id="myAspectAOP">
<aop:pointcut id="myPointcut" expression="execution(* aop.schema.MyBiz.*(..))"/>
</aop:aspect>
</aop:config>
</beans>

通知(Advice)

名称 说明
前置通知(Before advice) 在某连接点(join point)之前执行的通知,但不能阻止连接点前的执行(除非它抛出一个异常)
返回后通知(After returning advice) 在某连接点(join point)完成后执行的通知(不论是正常返回还是异常退出)
抛出异常后通知(After throwing advice) 在方法抛出异常退出时执行的通知
后通知(After(finally)advice) 当某连接点退出的时候执行的通知
环绕通知(Around Advice) 包围一个连接点(join point)的通知
1
2
3
4
5
6
7
8
9
10
11
12
try {
//@Before
result = method.invoke(target, args);
//@After
return result;
} catch (InvocationTargetException e) {
Throwable targetException = e.getTargetException();
//@AfterThrowing
throw targetException;
} finally {
//@AfterReturning
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean class="aop.schema.MyAspect" id="myAspect"/>
<bean class="aop.schema.MyBiz" id="myBiz"/>
<aop:config>
<!--以下两种配置方式等效-->
<!--------1------->
<aop:aspect ref="myAspect" id="myAspectAOP">
<aop:pointcut id="myPointcut" expression="execution(* aop.schema.MyBiz.*(..))"/>

<aop:before method="before" pointcut-ref="myPointcut"/>
<aop:after method="after" pointcut-ref="myPointcut"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="myPointcut"/>
<aop:after-returning method="afterReturning" pointcut-ref="myPointcut"/>
</aop:aspect>
<!--------2-------->
<aop:before method="before"
pointcut="execution(* aop.schema.MyBiz.*(..))"/>
<aop:after method="after"
pointcut="execution(* aop.schema.MyBiz.*(..))"/>
<aop:after-throwing method="afterThrowing"
pointcut="execution(* aop.schema.MyBiz.*(..))"/>
<aop:after-returning method="afterReturning"
pointcut="execution(* aop.schema.MyBiz.*(..))"/>

<!----------------->
</aop:config>
</beans>
  • Around advice

    • 通知方法的第一个参数必须是ProceedingJoinPoint类型

    • .xml

      1
      2
      3
      4
      5
      6
      <aop:config>
      <aop:aspect ref="myAspect" id="myAspectAOP">
      <aop:around method="around" pointcut="execution(* aop.schema.MyBiz.*(..))"/>
      </aop:aspect>
      </aop:config>.

.java

1
2
3
4
5
6
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
// start stopwatch
Object retVal = pjp.proceed();
// stop stopwatch
return retVal;
}

测试所用代码

  • 业务对象MyBiz2

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    package aop.schema.around;

    public class MyBiz2 {
    public void biz() {
    System.out.println("MyBiz:biz()");
    // throw new RuntimeException();
    }
    public void init(String bizName, int times) {
    System.out.println("MyBiz:init()" + " bizName:" + bizName + " times:" + times);
    }
    }
  • 切面对象MyParametersAdvice

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    package aop.schema.around;

    import org.aspectj.lang.ProceedingJoinPoint;

    public class MyParametersAdvice {

    public Object around(ProceedingJoinPoint pjp, String bizName, int times) throws Throwable {
    System.out.println("MyParametersAdvice:around()" + " bizName:" + bizName + " times:" + times);
    System.out.println("MyParametersAdvice: around() FirstPrint");
    Object obj = pjp.proceed();
    System.out.println("MyParametersAdvice: around() SecondPrint");
    return obj;
    }

    public void before() {
    System.out.println("MyParametersAdvice:before()");
    }

    public void afterReturning() {
    System.out.println("MyParametersAdvice:afterReturning()");
    }

    public void afterThrowing() {
    System.out.println("MyParametersAdvice:afterThrowing()");
    }

    public void after() {
    System.out.println("MyParametersAdvice:after()");
    }
    }
  • Spring配置文件 schema-around.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    <bean id="myParametersAdvice" class="aop.schema.around.MyParametersAdvice"/>
    <bean id="myBiz2" class="aop.schema.around.MyBiz2"/>
    <aop:config>
    <aop:aspect id="myParametersAdviceAOP" ref="myParametersAdvice">
    <aop:pointcut id="myPointcut" expression="execution(* aop.schema.around.MyBiz2.*(..))"/>

    <aop:before method="before" pointcut-ref="myPointcut"/>
    <aop:after-returning method="afterReturning" pointcut-ref="myPointcut"/>
    <aop:after-throwing method="afterThrowing" pointcut-ref="myPointcut"/>
    <aop:after method="after" pointcut-ref="myPointcut"/>

    <aop:around method="around"
    pointcut="execution(* aop.schema.around.MyBiz2.init(String,int)) and args(bizName,times)"/>
    </aop:aspect>
    </aop:config>
    </beans>
  • 测试类parametersAdviceTest 其继承的UnitTestBaseSpring中使用JUnit4的过度方法 中给出

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    package AOP.around;

    import aop.schema.around.MyBiz2;
    import beans.UnitTestBase;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.junit.runners.BlockJUnit4ClassRunner;

    @RunWith(BlockJUnit4ClassRunner.class)
    public class parametersAdviceTest extends UnitTestBase {
    public parametersAdviceTest() {
    super("AOP/schema-around.xml");
    }
    @Test
    public void test(){
    MyBiz2 myBiz2 = super.getBean("myBiz2");
    myBiz2.biz();
    System.out.println("*******************");
    myBiz2.init("testString",2);
    }
    }
  • 控制台输出结果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    MyParametersAdvice:before()
    MyBiz:biz()
    MyParametersAdvice:after()
    MyParametersAdvice:afterReturning()
    *******************
    MyParametersAdvice:before()
    MyParametersAdvice:around() bizName:testString times:2
    MyParametersAdvice: around() FirstPrint
    MyBiz:init() bizName:testString times:2
    MyParametersAdvice: around() SecondPrint
    MyParametersAdvice:after()
    MyParametersAdvice:afterReturning()

    Process finished with exit code 0