Spring-AOP 基于Schema配置切面

简介: Spring-AOP 基于Schema配置切面

概述


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


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


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


简单切面配置实例

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


示例


20170916095516410.jpg


首先来配置一个基于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>


解析:


使用一个<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");
    }
}

业务类

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");
    }
}


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");
    }
}

测试类

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();
    }
}


运行结果

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 execute


可见,切面被正确的实施到目标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)处使用<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定义的切面内容基本一致,只是在表现形式上存在差异罢了。

下面通过实例来演示


示例

20170916103444236.jpg

业务类

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");
    }
}


切面增强逻辑

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()----");
    }
}


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

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();
}
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 ");
    }
}
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();
}
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");
    }
}

配置文件

<?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>


测试类

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();
    }
}


运行结果

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 



重点说一下引介增强 : 通过<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)所有增强类型都可以通过可绑定参数的切点函数绑定连接点方法的入参。


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


20170916104610782.jpg

业务类

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);
    }
}


增强切面

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()----");
    }
}


配置文件

<?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>


切点表达式通过 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);
    }
}


运行结果

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
program:Spring, number:8
----bindJoinPointParams()----
name:Spring4
number:10
----bindJoinPointParams()----
BussinessBindParam fixBug executed
program:Spring4, number:10,salary20000.0


Advisor配置


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


20170916114604957.jpg


接口 及实现类

package com.xgj.aop.spring.advisor.schema.advisor;
public interface Waiter {
    void greetTo(String name);
    void serverTo(String name);
}


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);
    }
}

前置增强

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 + " ?");
    }
}


配置文件

<?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>

测试类

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");
    }
}


运行结果

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


相关文章
|
15小时前
|
存储 Java 数据安全/隐私保护
|
15小时前
|
安全 Java 开发者
深入理解Spring Boot配置绑定及其实战应用
【4月更文挑战第10天】本文详细探讨了Spring Boot中配置绑定的核心概念,并结合实战示例,展示了如何在项目中有效地使用这些技术来管理和绑定配置属性。
11 1
|
15小时前
|
XML Java 数据格式
Spring高手之路18——从XML配置角度理解Spring AOP
本文是全面解析面向切面编程的实践指南。通过深入讲解切面、连接点、通知等关键概念,以及通过XML配置实现Spring AOP的步骤。
22 6
Spring高手之路18——从XML配置角度理解Spring AOP
|
15小时前
|
消息中间件 开发框架 Java
什么是Spring Boot 自动配置?
Spring Boot 是一个流行的 Java 开发框架,它提供了许多便利的功能和工具,帮助开发者快速构建应用程序。其中一个最引人注目的特性是其强大的自动配置功能。
9 0
|
15小时前
|
Java Spring
Spring文件配置以及获取
Spring文件配置以及获取
13 0
|
15小时前
|
Java 微服务 Spring
Spring Boot中获取配置参数的几种方法
Spring Boot中获取配置参数的几种方法
22 2
|
15小时前
|
消息中间件 安全 Java
在Spring Bean中,如何通过Java配置类定义Bean?
【4月更文挑战第30天】在Spring Bean中,如何通过Java配置类定义Bean?
21 1
|
15小时前
|
Java 开发者 Spring
Spring Boot中的资源文件属性配置
【4月更文挑战第28天】在Spring Boot应用程序中,配置文件是管理应用程序行为的重要组成部分。资源文件属性配置允许开发者在不重新编译代码的情况下,对应用程序进行灵活地配置和调整。本篇博客将介绍Spring Boot中资源文件属性配置的基本概念,并通过实际示例展示如何利用这一功能。
24 1
|
15小时前
|
Java Spring 容器
如何用基于 Java 配置的方式配置 Spring?
如何用基于 Java 配置的方式配置 Spring?
|
15小时前
|
存储 前端开发 Java
第十一章 Spring Cloud Alibaba nacos配置中心
第十一章 Spring Cloud Alibaba nacos配置中心
26 0