SpringMVC 第十七章 基于 XML 的 AOP 开发


SpringMVC —— 第十七章 基于 XML 的 AOP 开发


1. 快速入门

  1. 导入 AOP 相关坐标
  2. 创建目标接口和目标类(内部有切点)
  3. 创建切面类(内部有增强方法)
  4. 将目标类和切面类的对象创建权限交给 Spring
  5. applicationContext.xml 中配置织入关系
  6. 测试代码

示例代码:

pom.xml

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.3.9</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.2</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>5.3.9</version>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13</version>
    <scope>test</scope>
</dependency>

applicationContext.xml

<?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 https://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- Target object -->
    <bean id="target" class="com.gregperlinli.aop.impl.Target">
    </bean>
    <!-- Aspect object -->
    <bean id="myAspect" class="com.gregperlinli.aop.MyAspect">
    </bean>
    <!-- Configuration weaving: Tell the spring framework which methods (pointcuts) need to be enhanced (pre, post, etc...) -->
    <aop:config>
        <!-- Declaration section -->
        <aop:aspect  ref="myAspect">
            <!-- Cut: pointcut + advice -->
            <aop:before method="front" pointcut="execution(public void com.gregperlinli.aop.impl.Target.save())" />
              <aop:after-returning method="post" pointcut="execution(public void com.gregperlinli.aop.impl.Target.save())" />
        </aop:aspect>
    </aop:config>
</beans>

com.yourname.aop.TargetInterface

/**
 * @author gregPerlinLi
 * @since 2021-09-15
 */
public interface TargetInterface &#123;
    /**
     * save
     */
     void save();
&#125;

com.yourname.aop.impl.Target

/**
 * @author gregPerlinLi
 * @since 2021-09-15
 */
public class Target implements TargetInterface &#123;
    @Override
    public void save() &#123;
        System.out.println("Save running...");
    &#125;
&#125;

com.yourname.aop.MyAspect

/**
 * @author gregPerlinLi
 * @since 2021-09-16
 */
public class MyAspect &#123;
    public void front() &#123;
        System.out.println("Front enhance...");
    &#125;
    public void post() &#123;
        System.out.println("Post enhance...");
    &#125;
&#125;

com.yourname.test.AopTest

/**
 * @author gregPerlinLi
 * @since 2021-09-16
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest &#123;
    @Autowired
    private TargetInterface target;
    @Test
    public void test1() &#123;
        target.save();
    &#125;
&#125;

2. XML 配置 AOP 详解

2.1. 切点表达式的写法

表达式语法:

execution([Modifer] returnType packageName.ClassName.methodName(parameters...))
  • 访问修饰符(Modifer)可以省略
  • 返回值类型、包名、类名、方法名可以使用星号 * 代表任意
  • 包名与类名之间一个点 . 代表当前包下的类,两个点 .. 代表当前包及其子包下的类
  • 参数列表可以使用两个点 .. 表示任意个数,任意类型的参数列表

例如:

execution(public void com.gregpelinli.aop.Target.method())
execution(void com.gregperlinli.aop.Target.*(..))
execution(* com.gregperlinli.aop.*.*(..))            
execution(* com.gregperlinli.aop..*.*(..))
execution(* *..*.*(..))

2.2. 通知的类型

通知的配置用法:

<aop:adviceType method="Method name in aspect class" poincut="pointcut expression"></aop:adviceType>
名称 标签 说明
前置通知 <aop:before> 用于配制前置通知,指定的增强方法在切入点方法之后执行
后置通知 <aop:after-returning> 用于配制后置通知,指定点增强方法在切入点方法之后执行
环绕通知 <aop:around> 用于配制环绕通知,指定增强方法在切入点之前和之后都执行
异常抛出通知 <aop:after-throwing> 用于配制异常抛出通知,指定增强方法在出现异常时执行
最终通知 <aop:after> 用于配制最终通知,无论增强方式是否执行是否有异常都会执行

示例代码:

applicationContext.xml

<?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 https://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- Target object -->
    <bean id="target" class="com.gregperlinli.aop.impl.Target">
    </bean>
    <!-- Aspect object -->
    <bean id="myAspect" class="com.gregperlinli.aop.MyAspect">
    </bean>
    <!-- Configuration weaving: Tell the spring framework which methods (pointcuts) need to be enhanced (pre, post, etc...) -->
    <aop:config>
        <!-- Declaration section -->
        <aop:aspect  ref="myAspect">
            <!-- Cut: pointcut + advice -->
            <aop:before method="before" pointcut="execution(* com.gregperlinli.aop..*.*(..))" />
            <aop:after-returning method="afterReturning" pointcut="execution(* com.gregperlinli.aop..*.*(..))" />
            <aop:around method="around" pointcut="execution(* com.gregperlinli.aop..*.*(..))" />
            <aop:after-throwing method="afterThrowing" pointcut="execution(* com.gregperlinli.aop..*.*(..))" />
            <aop:after method="after" pointcut="execution(* com.gregperlinli.aop..*.*(..))" />
        </aop:aspect>
    </aop:config>
</beans>

com.yourname.aop.impl.Target

/**
 * @author gregPerlinLi
 * @since 2021-09-15
 */
public class Target implements TargetInterface &#123;
    @Override
    public void save() &#123;
        // int i = 1/0;
        System.out.println("Save running...");
    &#125;
&#125;

com.yourname.aop.MyAspect

/**
 * @author gregPerlinLi
 * @since 2021-09-16
 */
public class MyAspect &#123;
    public void before() &#123;
        System.out.println("Front enhance...");
    &#125;
    public void afterReturning() &#123;
        System.out.println("Post enhance...");
    &#125;
    /**
     * @param pjp Executing joinpoint => pointcut
     */
    public Object around(ProceedingJoinPoint pjp) throws Throwable &#123;
        System.out.println("Before around enhance...");
        // Pointcut method
        Object proceed = pjp.proceed();
        System.out.println("After around enhance...");
        return proceed;
    &#125;
    public void afterThrowing() &#123;
        System.out.println("Throwing exception enhance...");
    &#125;
    public void after() &#123;
        System.out.println("Final enhance...");
    &#125;
&#125;

2.3. 切点表达式的抽取

当多个增强的切点表达式相同时,可以将切点表达式进行抽取,在增强中使用 poincut-ref 属性代替 poincut 属性来引用抽取后的切点表达式。

<!-- Configuration weaving: Tell the spring framework which methods (pointcuts) need to be enhanced (pre, post, etc...) -->
<aop:config>
    <!-- Declaration section -->
    <aop:aspect  ref="myAspect">
          <!-- Extract pointcut expression -->
          <aop:pointcut id="myPointcut" expression="execution(* com.gregperlinli.aop..*.*(..))"/>
        <!-- Cut: pointcut + advice -->
        <aop:before method="before" pointcut-ref="myPointcut" />
        <aop:after-returning method="afterReturning" pointcut-ref="myPointcut" />
        <aop:around method="around" pointcut-ref="myPointcut" />
        <aop:after-throwing method="afterThrowing" pointcut-ref="myPointcut" />
        <aop:after method="after" pointcut-ref="myPointcut" />
    </aop:aspect>
</aop:config>

3. 知识要点

  • AOP 织入配置:

      <aop:config>
           <aop:aspect ref="aspectClass">
                   <aop:adviceType method="Method name in aspect class" poincut="pointcut expression">            </aop:adviceType>
           </aop:aspect>
      </aop:config>
    
  • 通知的类型: 前置通知、后置通知、环绕通知、异常抛出通知、最终通知

  • 切点表达式的写法:

      execution([Modifer] returnType packageName.ClassName.methodName(parameters...))
    


文章作者: gregPerlinLi
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 gregPerlinLi !
  目录