在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