Spring-AOP 基于Schema配置切面

举报
小工匠 发表于 2021/09/10 23:16:07 2021/09/10
【摘要】 概述简单切面配置实例 示例 配置命名切点 示例 各种增强类型的配置 示例 绑定连接点信息Advisor配置 概述 如果项目不能使用Java5.0, ...

概述

如果项目不能使用Java5.0, 那么就无法使用基于@AspectJ注解的切面。 但是Spring提供了基于Schema配置的方法,它完全可以替代基于@AspectJ注解声明切面的方式。

基于@AspectJ注解的切面,本质上是将切点、增强类型的信息使用注解描述,我们将这两个信息转移到Schema的xml配置文件中,只是形式变了,本质还是相同的。

使用基于Schema的切面定义后,切点、增强类型的注解信息从切面类中剥离出来,原来的切面类也就蜕变为真正意义上的POJO了


简单切面配置实例

代码已托管到Github—> https://github.com/yangshangwei/SpringMaster


示例

这里写图片描述

首先来配置一个基于Schema的切面,它使用aop命名空间。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    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
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd">

<!-- (1)配置一个基于Schema的切面,它使用了aop命名空间, 因此首先声明aop及指定aop文件   如上-->

<!-- ref引用adviceMethods,紧接着声明切点表达式 以及增强方法使用adviceMethodsBean中的crossCutting方法-->
<aop:config proxy-target-class="true">
    <aop:aspect ref="adviceMethods">
        <aop:before  pointcut="target(com.xgj.aop.spring.advisor.schema.demo.BussinessOne) and execution(* program(..))" 
            method="crossCutting"/>
    </aop:aspect>
</aop:config>

<!-- 配置bean,也可以通过使用context命名空间扫描注解的方式实例化 -->
<bean id="bussinessOne" class="com.xgj.aop.spring.advisor.schema.demo.BussinessOne"/>
<bean id="bussinessTwo" class="com.xgj.aop.spring.advisor.schema.demo.BussinessTwo"/>
<!-- 增强方法所在的Bean -->
<bean id="adviceMethods" class="com.xgj.aop.spring.advisor.schema.demo.AdviceMethods"/>

</beans>

  
 
  • 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

解析:

  • 使用一个<aop:aspect>元素标签定义切面,其内部可以定义多个增强。

  • <aop:config>元素中可以定义多个切面。

  • 通过<aop:before>声明了一个前置增强,并通过pointcut属性定义切点表达式,切点表达式的语法和@AspectJ中所用的语法完全相同,由于&&在XML中使用不便,所以一般用and操作符代替。

  • 通过method属性指定增强的方法,该方法应该是adviceMethods Bean中的方法。


AdviceMethods是增强方法所在的类,它是一个普通的java类,没有任何特殊的地方,如下

package com.xgj.aop.spring.advisor.schema.demo;

/**
 * 
 * 
 * @ClassName: AdviceMethods
 * 
 * @Description: 增强方法所在的Bean
 * 
 * @author: Mr.Yang
 * 
 * @date: 2017年9月13日 下午4:38:25
 */

public class AdviceMethods {

    /**
     * 
     * 
     * @Title: crossCutting
     * 
     * @Description: 改方法通过配置被用作增强方法
     * 
     * 
     * @return: void
     */
    public void crossCutting() {
        System.out.println("crossCutting executed");
    }
}

  
 
  • 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
  • 31

业务类

package com.xgj.aop.spring.advisor.schema.demo;

/**
 * 
 * 
 * @ClassName: BussinessOne
 * 
 * @Description: 普通POJO
 * 
 * @author: Mr.Yang
 * 
 * @date: 2017年9月13日 下午4:37:56
 */

public class BussinessOne {

    public void program() {
        System.out.println("BussinessOne program executed");
    }

    public void fixBug() {
        System.out.println("BussinessOne fixBug executed");
    }
}

  
 
  • 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
package com.xgj.aop.spring.advisor.schema.demo;

/**
 * 
 * 
 * @ClassName: BussinessTwo
 * 
 * @Description: 普通POJO
 * 
 * @author: Mr.Yang
 * 
 * @date: 2017年9月13日 下午4:38:10
 */

public class BussinessTwo {
    public void program() {
        System.out.println("BussinessOne program executed");
    }

    public void fixBug() {
        System.out.println("BussinessOne fixBug executed");
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

测试类

package com.xgj.aop.spring.advisor.schema.demo;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ConfigBySchemaTest {

    @Test
    public void test() {
        ApplicationContext ctx = new ClassPathXmlApplicationContext(
                "classpath:com/xgj/aop/spring/advisor/schema/demo/conf-bySchema.xml");

        BussinessOne bussinessOne = ctx.getBean("bussinessOne",
                BussinessOne.class);
        BussinessTwo bussinessTwo = ctx.getBean("bussinessTwo",
                BussinessTwo.class);

        // 根据配置文件中的切点表达式
        // target(com.xgj.aop.spring.advisor.schema.demo.BussinessOne)and
        // execution(* program(..)) ,只有
        // bussinessOne.program()符合条件
        bussinessOne.program();
        bussinessOne.fixBug();

        bussinessTwo.program();
        bussinessTwo.fixBug();

    }

}

  
 
  • 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
  • 31
  • 32

运行结果

2017-09-15 22:01:42,550  INFO [main] (AbstractApplicationContext.java:583) - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@61ee30d2: startup date [Fri Sep 15 22:01:42 BOT 2017]; root of context hierarchy
2017-09-15 22:01:42,704  INFO [main] (XmlBeanDefinitionReader.java:317) - Loading XML bean definitions from class path resource [com/xgj/aop/spring/advisor/schema/demo/conf-bySchema.xml]
crossCutting executed
BussinessOne program executed
BussinessOne fixBug executed
BussinessOne program executed
BussinessOne fixBug executed
  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

可见,切面被正确的实施到目标Bean中。


配置命名切点

上面的例子中通过pointcut属性声明的切点时匿名切点,它不能被其他增强或其他切面引用。Spring提供了命名切点的配置方式。

示例

<aop:config proxy-target-class="true">
    <!-- (1) --->
    <aop:pointcut id="bussinessOneProgram"   expression="target(com.xgj.aop.spring.advisor.schema.namePointcut.BussinessOne) and execution(* program(..))" />

    <aop:aspect ref="adviceMethods">
        <!-- (2) --->
        <aop:before  pointcut-ref="bussinessOneProgram" method="crossCutting"/>
    </aop:aspect>
</aop:config>
  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 在(1)处使用<aop:pointcut>定义了一个切点,并通过id属性进行命名.
    • 在(2)通过pointcut-ref引用这个命名的切点。和<aop:before>一样,除了引介增强外,其他任意增强类型都拥有pointcut、pointcut-ref和method这3个属性。

    当然了,<aop:pointcut>如果位于<aop:aspect>元素中,则该命名切点只能被当前<aop:aspect>内定义的元素访问到。 为了能让整个<aop:config>元素中定义的所有增强访问,必须在<aop:config>元素下定义切点,如上所示。

    如果有在<aop:config>元素下直接定义<aop:pointcut>,则必须保证 <aop:pointcut><aop:aspect>之前定义。 在 <aop:config>元素下还可以定义 <aop:advisor>,三者的顺序要求为:首先是<aop:pointcut>,然后是 <aop:advisor>,最后是<aop:aspect>


各种增强类型的配置

基于Schema定义的切面和基于@AspectJ定义的切面内容基本一致,只是在表现形式上存在差异罢了。

下面通过实例来演示

示例

这里写图片描述

业务类

package com.xgj.aop.spring.advisor.schema.advices;

public class BussinessSvc {

    public void dealBussinessBefore() {
        System.out.println("dealBussinessBefore executed");
    }

    public int dealWorkNumberForAfterReturring() {
        System.out.println("dealWorkNumberForAfterReturring executed");
        return 10;
    }

    public void dealWorkForAround(String workName) {
        System.out.println("dealWorkForAround executed");
    }

    public void dealBussinessForAfterThorowing(String bussinessName) {
        System.out.println("dealBussinessForAfterThorowing executed");
        // just a demo code ,in fact it's not cautious
        if (bussinessName != null && "bug".equals(bussinessName))
            throw new IllegalArgumentException("iae Exception");
        else
            throw new RuntimeException("re Exception");
    }

    public void dealWorkForAfter() {
        System.out.println("dealWorkForAfter executed");
    }
}

  
 
  • 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
  • 31

切面增强逻辑

package com.xgj.aop.spring.advisor.schema.advices;

import org.aspectj.lang.ProceedingJoinPoint;

public class AdviceMethods {
    /**
     * 
     * 
     * @Title: before
     * 
     * @Description: 前置增强对应的方法
     * 
     * @param name
     * 
     * @return: void
     */
    public void beforeMethod() {
        System.out.println("--Before CrossCuttingCode--");
    }

    /**
     * 
     * 
     * @Title: afterReturning
     * 
     * @Description: 后置增强对应方法 ,配置文件中的returing属性必须和增强方法的入参名称一致
     * 
     * @param retVal
     * 
     * @return: void
     */
    public void afterReturningMethod(int retVal) {
        System.out.println("----afterReturning() begin----");
        System.out.println("returnValue:" + retVal);
        System.out.println("----afterReturning() end----");
    }

    /**
     * 
     * 
     * @Title: aroundMethod
     * 
     * @Description: 环绕增强对应方法
     * 
     * @param pjp
     * 
     * @return: void
     * @throws Throwable
     */
    public void aroundMethod(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("----aroundMethod() begin----");
        System.out.println("args[0]:" + pjp.getArgs()[0]);
        // 执行目标类的目标方法
        pjp.proceed();
        System.out.println("----aroundMethod() end----");
    }

    /**
     * 
     * 
     * @Title: afterThrowingMethod
     * 
     * @Description: 抛出异常增强
     * 
     * @param iae
     * 
     * @return: void
     */
    public void afterThrowingMethod(IllegalArgumentException iae) {
        System.out.println("----afterThrowingMethod()----");
        System.out.println("exception msg:" + iae.getMessage());
        System.out.println("----afterThrowingMethod()----");
    }

    /**
     * 
     * 
     * @Title: afterMethod
     * 
     * @Description: final增强
     * 
     * 
     * @return: void
     */
    public void afterMethod() {
        System.out.println("----afterMethod()----");
    }
}

  
 
  • 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
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89

为了演示引介增强引入的几个接口和实现类

package com.xgj.aop.spring.advisor.schema.advices;

/**
 * 
 * 
 * @ClassName: InterfaceOne
 * 
 * @Description: 演示引介增强用
 * 
 * @author: Mr.Yang
 * 
 * @date: 2017年9月13日 下午8:14:18
 */
public interface InterfaceOne {
    void dealAnotherWork();
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
package com.xgj.aop.spring.advisor.schema.advices;

/**
 * 
 * 
 * @ClassName: InterfaceOneImpl
 * 
 * @Description: 演示引介增强用
 * 
 * @author: Mr.Yang
 * 
 * @date: 2017年9月13日 下午8:14:33
 */
public class InterfaceOneImpl implements InterfaceOne {

    @Override
    public void dealAnotherWork() {
        System.out.println("InterfaceOneImpl dealAnotherWork executed ");

    }

}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
package com.xgj.aop.spring.advisor.schema.advices;

/**
 * 
 * 
 * @ClassName: IntfBussiness
 * 
 * @Description: 演示引介增强用
 * 
 * @author: Mr.Yang
 * 
 * @date: 2017年9月13日 下午8:14:41
 */
public interface IntfBussiness {
    void fixBug();
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
package com.xgj.aop.spring.advisor.schema.advices;

/**
 * 
 * 
 * @ClassName: IntfBussinessImpl
 * 
 * @Description: 演示引介增强用
 * 
 * @author: Mr.Yang
 * 
 * @date: 2017年9月13日 下午8:14:49
 */
public class IntfBussinessImpl implements IntfBussiness {

    @Override
    public void fixBug() {
        System.out.println("IntfBussinessImpl  fixBug executed");
    }

}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    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
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd">

    <aop:config proxy-target-class="true">
        <!-- 前置增强命名切点 -->
        <aop:pointcut expression="execution(* dealBussinessBefore(..))" id="before" />
        <!-- 后置增强命名切点 -->
        <aop:pointcut expression="execution(* dealWorkNumberForAfterReturring(..))" id="afterReturnning" />
        <!-- 环绕增强命名切点 -->
        <aop:pointcut expression="execution(* dealWorkForAround(..)) and within(com.xgj.aop.spring.advisor.schema.advices.BussinessSvc)" id="around" />
        <!-- 异常抛出命名切点 -->
        <aop:pointcut expression="within(com.xgj.aop.spring.advisor.schema.advices.BussinessSvc) and execution(* dealBussinessForAfterThorowing(..))"  id="afterThrowing"/>
        <!-- final抛出命名切点 -->
        <aop:pointcut expression="execution(* dealWorkForAfter(..))" id="after"/>
        <!-- 引介增强不同,另述 -->

        <aop:aspect ref="adviceMethods">
            <!-- 前置增强 -->
            <aop:before pointcut-ref="before" method="beforeMethod" />
            <!-- 后置增强 -->
            <aop:after-returning pointcut-ref="afterReturnning"
                method="afterReturningMethod" returning="retVal" />
            <!-- 环绕增强 -->
            <aop:around pointcut-ref="around" method="aroundMethod"/>
            <!-- 异常抛出增强 -->
            <aop:after-throwing pointcut-ref="afterThrowing" method="afterThrowingMethod"  throwing="iae"/>
            <!-- final增强 -->
            <aop:after pointcut-ref="after" method="afterMethod"/>

            <!-- 引介增强  types-matching哪些类需要引介接口的实现  implement-interface要引介实现的接口   default-impl 引介默认的实现类-->
            <aop:declare-parents 
                types-matching="com.xgj.aop.spring.advisor.schema.advices.IntfBussiness+" 
                implement-interface="com.xgj.aop.spring.advisor.schema.advices.InterfaceOne"
                default-impl="com.xgj.aop.spring.advisor.schema.advices.InterfaceOneImpl"/>
        </aop:aspect>
    </aop:config>
    <!-- 业务类 -->
    <bean id="bussinessSvc" class="com.xgj.aop.spring.advisor.schema.advices.BussinessSvc" />
    <bean id="intfBussinessImpl" class="com.xgj.aop.spring.advisor.schema.advices.IntfBussinessImpl"></bean>
    <!-- 增强类 -->
    <bean id="adviceMethods" class="com.xgj.aop.spring.advisor.schema.advices.AdviceMethods" />
</beans>

  
 
  • 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
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

测试类

package com.xgj.aop.spring.advisor.schema.advices;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class DifferentAdviceTest {

    @Test
    public void test() {
        ApplicationContext ctx = new ClassPathXmlApplicationContext(
                "classpath:com/xgj/aop/spring/advisor/schema/advices/conf-advices.xml");

        BussinessSvc bussinessSvc = ctx.getBean("bussinessSvc",
                BussinessSvc.class);
        // 方法执行前织入前置增强
        bussinessSvc.dealBussinessBefore();

        // 方法执行后织入后置增强
        bussinessSvc.dealWorkNumberForAfterReturring();

        // 方法执行时织入环绕增强
        bussinessSvc.dealWorkForAround("fixBug");

        // 方法执行时出现特定异常时织入异常抛出增强
        bussinessSvc.dealWorkForAfter();

        // 方法执行后,不管异常与否都执行的增强
        bussinessSvc.dealWorkForAfter();

        // 引介 --强制类型转换成功,说明也实现了另外的接口
        IntfBussinessImpl intfBussinessImpl = ctx.getBean("intfBussinessImpl",
                IntfBussinessImpl.class);
        ((InterfaceOne) intfBussinessImpl).dealAnotherWork();
    }
}

  
 
  • 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
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

运行结果

2017-09-15 22:37:49,383  INFO [main] (AbstractApplicationContext.java:583) - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@c24cb3: startup date [Fri Sep 15 22:37:49 BOT 2017]; root of context hierarchy
2017-09-15 22:37:49,485  INFO [main] (XmlBeanDefinitionReader.java:317) - Loading XML bean definitions from class path resource [com/xgj/aop/spring/advisor/schema/advices/conf-advices.xml]
--Before CrossCuttingCode--
dealBussinessBefore executed
dealWorkNumberForAfterReturring executed
----afterReturning() begin----
returnValue:10
----afterReturning() end----
----aroundMethod() begin----
args[0]:fixBug
dealWorkForAround executed
----aroundMethod() end----
dealWorkForAfter executed
----afterMethod()----
dealWorkForAfter executed
----afterMethod()----
InterfaceOneImpl dealAnotherWork executed 

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

重点说一下引介增强 : 通过<aop:declare-parent>配置引介增强, 引介增强和其他类型的增强有所不同,它没有method、pointcut和point-ref属性

引介增强通过types-matching以及AspectJ切点表达式语法指定哪些bean需要引介接口的实现, implement-interface要引介实现的接口 , default-impl 引介默认的实现类

值的注意的是,虽然<aop:declare-parent>么有method属性指定增强方法所在的Bean,但是<aop:aspect ref="adviceMethods">中的ref属性依然要指定一个增强Bean。


绑定连接点信息

基于Schema配置的增强方法绑定连接点信息和基于@AspectJ绑定连接点信息所使用的方式没有区别。

  • 1)所有增强类型对应的方法第一个入参都可以声明为JoinPoint(环绕增强可声明为ProceedingJoinPoint)访问连接点信息;

  • 2)<aop:after-returning>(后置增强)可以通过returning属性绑定连接点方法的返回值,<aop:after-throwing>(抛出异常增强)可以通过throwing属性绑定连接点方法所抛出的异常;

  • 3)所有增强类型都可以通过可绑定参数的切点函数绑定连接点方法的入参。

前两种已经阐述过了,下面我们来看第三种绑定参数的方法

这里写图片描述

业务类

package com.xgj.aop.spring.advisor.schema.bindParameter;

import org.springframework.stereotype.Component;

/**
 * 
 * 
 * @ClassName: BussinessBindParam
 * 
 * @Description: 使用注解定义的Bean
 * 
 * @author: Mr.Yang
 * 
 * @date: 2017年9月13日 下午8:25:23
 */

@Component
public class BussinessBindParam {

    public void program(String name, int number) {
        System.out.println("BussinessBindParam program execute");
        System.out.println("program:" + name + ", number:" + number);
    }

    public void fixbug(String name, int number, double salary) {
        System.out.println("BussinessBindParam fixBug executed");
        System.out.println("program:" + name + ", number:" + number + ",salary"
                + salary);
    }
}

  
 
  • 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
  • 31

增强切面

package com.xgj.aop.spring.advisor.schema.bindParameter;

import org.springframework.stereotype.Component;

/**
 * 
 * 
 * @ClassName: AdviceMethodsBindParam
 * 
 * @Description: 使用注解定义的Bean,同时也是切面类
 * 
 * @author: Mr.Yang
 * 
 * @date: 2017年9月13日 下午8:25:13
 */

@Component
public class AdviceMethodsBindParam {

    /**
     * 
     * 
     * @Title: crossCutting
     * 
     * @Description: 改方法通过配置被用作增强方法
     * 
     * 
     * @return: void
     */
    public void crossCutting(String name, int num) {
        System.out.println("----bindJoinPointParams()----");
        System.out.println("name:" + name);
        System.out.println("number:" + num);
        System.out.println("----bindJoinPointParams()----");
    }
}

  
 
  • 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
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    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
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd">

<!-- (1)配置一个基于Schema的切面,它使用了aop命名空间, 因此首先声明aop及指定aop文件   如上-->

<!-- ref引用adviceMethods,紧接着引用命名切点 以及增强方法使用adviceMethodsBean中的crossCutting方法-->
<aop:config proxy-target-class="true">
    <!-- 定义切点 -->
    <aop:pointcut id="bussinessBindParamProgram" expression="target(com.xgj.aop.spring.advisor.schema.bindParameter.BussinessBindParam) and args(name,num,..)" />

    <aop:aspect ref="adviceMethodsBindParam">
        <aop:before  pointcut-ref="bussinessBindParamProgram" method="crossCutting"/>
    </aop:aspect>
</aop:config>

<!-- 扫描类包以及使用注解定义的bean -->
<context:component-scan base-package="com.xgj.aop.spring.advisor.schema.bindParameter"/>
</beans>

  
 
  • 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

切点表达式通过 args(name,num,..) 绑定了连接点的两个参数,对应增强类中的入参crossCutting(String name, int num) . 这两个地方声明的参数名必须相同

测试类

package com.xgj.aop.spring.advisor.schema.bindParameter;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AdviceMethodsBindParamTest {
    @Test
    public void test() {
        ApplicationContext ctx = new ClassPathXmlApplicationContext(
                "classpath:com/xgj/aop/spring/advisor/schema/bindParameter/conf-bindParam.xml");

        BussinessBindParam bussinessBindParam = ctx.getBean(
                "bussinessBindParam", BussinessBindParam.class);
        // args(name,num,..) 因此会匹配到
        bussinessBindParam.program("Spring", 8);

        // args(name,num,..) 因此会匹配到
        bussinessBindParam.fixbug("Spring4", 10, 20000);
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

运行结果

2017-09-15 22:47:49,244  INFO [main] (AbstractApplicationContext.java:583) - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@6ac604: startup date [Fri Sep 15 22:47:49 BOT 2017]; root of context hierarchy
2017-09-15 22:47:49,350  INFO [main] (XmlBeanDefinitionReader.java:317) - Loading XML bean definitions from class path resource [com/xgj/aop/spring/advisor/schema/bindParameter/conf-bindParam.xml]
----bindJoinPointParams()----
name:Spring
number:8
----bindJoinPointParams()----
BussinessBindParam program execute
programSpring, number:8
----bindJoinPointParams()----
name:Spring4
number:10
----bindJoinPointParams()----
BussinessBindParam fixBug executed
programSpring4, number:10,salary20000.0

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

Advisor配置

Advisor是Spring中切面概念的对应物,是切点和增强的复合体,不过仅包含一个切点和一个增强。在AspectJ中没有对应的等价物,在aop Schema配置样式中,可以通过配置一个Advisor。通过advice-ref属性引用基于接口定义的增强,通过pointcut定义切点表达式,或者通过pointcut-ref引用一个命名的切点。

这里写图片描述

接口 及实现类

package com.xgj.aop.spring.advisor.schema.advisor;

public interface Waiter {

    void greetTo(String name);

    void serverTo(String name);
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
package com.xgj.aop.spring.advisor.schema.advisor;

import org.springframework.stereotype.Component;

@Component
public class NaiveWaiter implements Waiter {

    @Override
    public void greetTo(String name) {
        System.out.println("greetTo " + name + "\n");
    }

    @Override
    public void serverTo(String name) {
        System.out.println("serverTo " + name);
    }

}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

前置增强

package com.xgj.aop.spring.advisor.schema.advisor;

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;

/**
 * 
 * 
 * @ClassName: GreetingBeforeAdvice
 * 
 * @Description: 前置增强
 * 
 * @author: Mr.Yang
 * 
 * @date: 2017年9月13日 下午8:55:12
 */

public class GreetingBeforeAdvice implements MethodBeforeAdvice {

    /**
     * 前置增强方法 当该方法发生异常时,将阻止目标方法的执行
     * 
     * @param method
     *            目标类方法
     * @param objects
     *            目标类方法入参
     * @param target
     *            目标类对象实例
     * @throws Throwable
     */
    @Override
    public void before(Method method, Object[] args, Object target)
            throws Throwable {
        String clientName = (String) args[0];
        System.out.println("How are you " + clientName + " ?");
    }
}

  
 
  • 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
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    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
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd">

<!-- (1)配置一个基于Schema的切面,它使用了aop命名空间, 因此首先声明aop及指定aop文件   如上-->

<!-- ref引用adviceMethods,紧接着引用命名切点 以及增强方法使用adviceMethodsBean中的crossCutting方法-->
<aop:config proxy-target-class="true">
    <!-- 命名切点 -->
    <aop:pointcut expression="execution(* com..*.Waiter.greetTo(..))" id="beforeAdvice"/>

    <aop:advisor advice-ref="greetingBeforeAdvice" pointcut-ref="beforeAdvice"/>

</aop:config>

<!-- 扫描类包以及使用注解定义的bean -->
<context:component-scan base-package="com.xgj.aop.spring.advisor.schema.advisor"/>
<!-- advice -->
<bean id="greetingBeforeAdvice" class="com.xgj.aop.spring.advisor.schema.advisor.GreetingBeforeAdvice"/>
</beans>

  
 
  • 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

测试类

package com.xgj.aop.spring.advisor.schema.advisor;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AdvisorTest {
    @Test
    public void test() {
        ApplicationContext ctx = new ClassPathXmlApplicationContext(
                "classpath:com/xgj/aop/spring/advisor/schema/advisor/conf-advisor.xml");

        NaiveWaiter naiveWaiter = ctx.getBean("naiveWaiter", NaiveWaiter.class);
        naiveWaiter.greetTo("XiaoGongJiang");
        naiveWaiter.serverTo("XiaoGongJiang");

    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

运行结果

2017-09-15 23:47:57,497  INFO [main] (AbstractApplicationContext.java:583) - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@61ee30d2: startup date [Fri Sep 15 23:47:57 BOT 2017]; root of context hierarchy
2017-09-15 23:47:57,599  INFO [main] (XmlBeanDefinitionReader.java:317) - Loading XML bean definitions from class path resource [com/xgj/aop/spring/advisor/schema/advisor/conf-advisor.xml]
How are you XiaoGongJiang ?
greetTo XiaoGongJiang

serverTo XiaoGongJiang

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

文章来源: artisan.blog.csdn.net,作者:小小工匠,版权归原作者所有,如需转载,请联系作者。

原文链接:artisan.blog.csdn.net/article/details/78001436

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。