Spring AOP基于注解的Demo

在XML文件里配置AOP的各种切面配置比较麻烦,也可以直接通过注解来完成

首先是Pointcut,声明一个接口

package com.lihuia.aop.annotation;

/**
 * Copyright (C), 2018-2019
 * FileName: Hello
 * Author:   lihui
 * Date:     2019/2/10
 */

public interface Hello {
 
    void sayHello();
}

接口的实现类如下

package com.lihuia.aop.annotation;

/**
 * Copyright (C), 2018-2019
 * FileName: HelloImpl
 * Author:   lihui
 * Date:     2019/2/11
 */

public class HelloImpl implements Hello {
 
    @Override
    public void sayHello() {
        System.out.println("Hello World");
    }
}

使用注解,切点表达式里的sayHello()方法被调用即可触发切面

"execution(* com.lihuia.aop.annotation.Hello.sayHello(..))"

定义切面,举个例子,比如我们在sayHello()之前还不是Friends,sayHello()了之后才是Friends

具体Advice的含义如下

那么在sayHello()被调用就会触发切面,切点表达式作为参数传入Advice各个注解,具体就会执行Advice注解的方法

package com.lihuia.aop.annotation;

import org.aspectj.lang.annotation.*;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
* Copyright (C), 2018-2019
* FileName: Friend
* Author: lihui
* Date: 2019/2/11
*/

@Aspect
public class Friend {

@Before("execution(* com.lihuia.aop.annotation.Hello.sayHello(..))")
public void beforeFriends() {
System.out.println("BeforeFriends: " +
new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss:SSS").format(new Date()));
}

@AfterReturning("execution(* com.lihuia.aop.annotation.Hello.sayHello(..))")
public void afterReturningFriends() {
System.out.println("AfterReturningFriends: " +
new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss:SSS").format(new Date()));
}

@After("execution(* com.lihuia.aop.annotation.Hello.sayHello(..))")
public void afterFriends() {
System.out.println("AfterFriends: " +
new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss:SSS").format(new Date()));
}

@AfterThrowing("execution(* com.lihuia.aop.annotation.Hello.sayHello(..))")
public void afterThrowingTime() {
System.out.println("AfterThrowingFriends: " +
new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss:SSS").format(new Date()));
}
}

同时也可以定义一个命名切点,通过一个hello()方法来使用@Pointcut注解,这样任何切点表达式都可以直接使用hello()来标志

package com.lihuia.aop.annotation;

import org.aspectj.lang.annotation.*;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
* Copyright (C), 2018-2019
* FileName: Friend
* Author: lihui
* Date: 2019/2/11
*/

@Aspect
public class Friend {

@Pointcut("execution(* com.lihuia.aop.annotation.Hello.sayHello(..))")
public void hello() {

}

@Before("hello()")
public void beforeFriends() {
System.out.println("BeforeFriends: " +
new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss:SSS").format(new Date()));
}

@AfterReturning("hello()")
public void afterReturningFriends() {
System.out.println("AfterReturningFriends: " +
new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss:SSS").format(new Date()));
}

@After("hello()")
public void afterFriends() {
System.out.println("AfterFriends: " +
new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss:SSS").format(new Date()));
}

@AfterThrowing("hello()")
public void afterThrowingTime() {
System.out.println("AfterThrowingFriends: " +
new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss:SSS").format(new Date()));
}
}

具体XML里配置

aop:aspectj-autoproxy元素,启用AspectJ自动代理

AspectJ自动代理会给@Aspect注解的bean创建一个代理,这个代理会围绕着所有该切面的切点所匹配的bean,如此一来,将会给bean创建一个代理,Friend类中的通知方法将会在hello()调用前后执行

<?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"
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-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">

<bean id="hello" class="com.lihuia.aop.annotation.HelloImpl"></bean>

<context:component-scan base-package="com.lihuia.aop.annotation"></context:component-scan>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<bean class="com.lihuia.aop.annotation.Friend"></bean>
</beans>

添加测试类

package com.lihuia.aop.annotation;

import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.annotations.Test;

import javax.annotation.Resource;

/**
* Copyright (C), 2018-2019
* FileName: AopTest
* Author: lihui
* Date: 2019/2/11
*/

@ContextConfiguration(locations = {
"classpath*:aopAnnotation.xml"
})
public class AopTest extends AbstractTestNGSpringContextTests {

@Resource
private Hello hello;

@Test(description = "基于注解的AOP")
public void aopTest() {
hello.sayHello();
}

}

运行结果

BeforeFriends: 2019-02-11-02:16:06:383
Hello World
AfterFriends: 2019-02-11-02:16:06:386
AfterReturningFriends: 2019-02-11-02:16:06:388

这样切点处通知的触发都OK

发表回复