1. 概述

在本文,我们将讨论spring aop通知中的前置通知(Before advice)。

将分别使用 AspectJ @Before注解和XML配置的方式使用前置通知。

2. 前置通知

在连接点的前面执行,前置通知不会影响连接点的执行,除非在前置通知处理中抛出异常。

在下面的示例中,我们将创建简单的spring应用程序,添加日志记录的切面。

关于POM的依赖可以参考前面的文章

3. 使用 @Before注解

我们直接使用@Before注解来定义前置通知。

@Aspect
@Component
public class LogAspect {

    @Before("execution(* com.ripjava.spring.aop.ann.services.EmployeeManager..*(..))")
    public void logBeforeAllMethods(JoinPoint joinPoint) {
        System.out.println("LogAspect.logBeforeAllMethods() : " + joinPoint.getSignature().getName());
    }

    @Before("execution(* com.ripjava.spring.aop.ann.services.EmployeeManager.getEmployeeById(..))")
    public void logBeforeGetEmployee(JoinPoint joinPoint) {
        System.out.println("LogAspect.logBeforeGetEmployeeById() : " + joinPoint.getSignature().getName());
    }
}

因为我们这里使用的注解的方式配置Spring,我们还需要定义一个配置类:

@Configuration
@ComponentScan(basePackageClasses = {BeforeConfig.class, EmployeeManager.class})
@EnableAspectJAutoProxy
public class BeforeConfig {
}

最后,我们来测试一下:

@Test
public void test_Aspect_Before(){
  ApplicationContext context
    = new AnnotationConfigApplicationContext(BeforeConfig.class);
  EmployeeManager manager = context.getBean(EmployeeManager.class);
  manager.getEmployeeById(1);
  manager.createEmployee(new EmployeeDTO());
}

输出如下:

LogAspect.logBeforeAllMethods() : getEmployeeById
LogAspect.logBeforeGetEmployeeById() : getEmployeeById
Method getEmployeeById() called
LogAspect.logBeforeAllMethods() : createEmployee
Method createEmployee() called

4. 使用XML配置

下面我们来使用XML定义一个前置通知。

Java代码,我们直接使用上面的就好,这里我们只需要配置一个XML就好。

<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 ">
    
    <aop:config>
        <aop:aspect ref="loggingAspect">
            <aop:pointcut expression="execution(* com.ripjava.spring.aop.ann.services.EmployeeManager.*(..))"
                          id="loggingAllMethodsPointcuts"/>
            <aop:pointcut expression="execution(* com.ripjava.spring.aop.ann.services.EmployeeManager.getEmployeeById(..))"
                          id="loggingGetEmployeeByIdPointcuts"/>
            <!-- 前置通知 -->
            <aop:before method="logBeforeAllMethods" pointcut-ref="loggingAllMethodsPointcuts" />
            <aop:before method="logBeforeGetEmployee" pointcut-ref="loggingGetEmployeeByIdPointcuts" />
        </aop:aspect>
    </aop:config>
    
    <bean id="employeeManager" class="com.ripjava.spring.aop.ann.services.EmployeeManager" />
    
    <bean id="loggingAspect" class="com.ripjava.spring.aop.ann.before.LogAspect" />

</beans>

最后,我们来测试一下:

@Test
public void test_Aspect_BeforeByXML(){
  ApplicationContext context = new ClassPathXmlApplicationContext("spring-aop-before.xml");
  EmployeeManager manager = context.getBean(EmployeeManager.class);
  manager.getEmployeeById(1);
  manager.createEmployee(new EmployeeDTO());
}

输出如下:

LogAspect.logBeforeAllMethods() : getEmployeeById
LogAspect.logBeforeGetEmployeeById() : getEmployeeById
Method getEmployeeById() called
LogAspect.logBeforeAllMethods() : createEmployee
Method createEmployee() called

我们发现和刚才输出的一致。

5. 总结

在本文,我们分别通过使用注解和XML的方式,展示了spring aop通知中的前置通知(Before advice)的简单用法。

最后,和往常一样,代码可以在Github上找到。