目录
1.2、创建一个service,使用上面定义的注解来指定切点
1.3、创建Aspect,增加业务逻辑
1.4、创建Spring配置类
1.5、测试
2.1、创建带属性的自定义注解
2.3、创建Aspect的错误示例
2.4、创建Aspect的正确做法
2.5、测试
三、总结
一、利用注解实现AOP的基本流程
如果特别熟悉自定义注解实现AOP,可以直接转到第二部分:跳转。
Spring中,可以通过自定义注解的方式来实现AOP,比较简单,流程如下:
1.1、创建一个注解,用来注解切点(pointcut)
package cn.ganlixin.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DemoAnnotation {
//注意这里没有定义属性
}
1.2、创建一个service,使用上面定义的注解来指定切点
这里为了节约篇幅,就不创建service接口,再创建serviceImpl来实现接口了,直接写在service中:
package cn.ganlixin.service;
import cn.ganlixin.annotation.DemoAnnotation;
import org.springframework.stereotype.Service;
@Service
public class DemoService {
@DemoAnnotation // 使用自定义的注解,声明该方法为切点方法
public void demo() {
System.out.println("this is DemoService.demo()");
}
}
1.3、创建Aspect,增加业务逻辑
package cn.ganlixin.aspect;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class DemoAspect {
@Before("@annotation(cn.ganlixin.annotation.DemoAnnotation)")
public void demoBefore() {
System.out.println("this is before output message");
}
}
1.4、创建Spring配置类
主要做的是:指定包扫描路径
package cn.ganlixin;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@ComponentScan("cn.ganlixin")
@EnableAspectJAutoProxy
public class AppConfig {
}
1.5、测试
package cn.ganlixin;
import cn.ganlixin.service.DemoService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class AppTest {
@Test
public void testAOP1() {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
DemoService demoService = context.getBean(DemoService.class);
demoService.demo();
}
}
输出:
this is before output message
this is DemoService.demo()
二、获取自定义注解的参数
2.1、创建带属性的自定义注解
要获取自定义注解参数,就需要在自定义注解中增加几个属性,下面自定义的TestAnnotation中有两个属性:value和description。
package cn.ganlixin.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface TestAnnotation {
String value();
String description() default "default description";
}
2.2、创建service使用带属性的自定义注解
service中有两个方法,分别使用了自定义注解:
package cn.ganlixin.service;
import cn.ganlixin.annotation.TestAnnotation;
import org.springframework.stereotype.Service;
@Service
public class TestService {
@TestAnnotation("this is value")
public void test1() {
System.out.println("this is TestService.test1()");
}
@TestAnnotation(value = "this is another value", description = "this is description")
public void test2() {
System.out.println("this is TestService.test2()");
}
}
2.3、创建Aspect的错误示例
在写博客之前,我也搜过相关的博客,但是发现很多博客中写的都是利用@Around来实现获取注解信息,但是我如果需要在@Before中,@After中获取又怎么办呢?虽然可以通过以下骚操作,通过@Around来模拟@Before和@After,但是还是感觉不好。
下面还是使用@Before来实现的。
package cn.ganlixin.aspect;
import cn.ganlixin.annotation.TestAnnotation;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class TestAspect {
@Before("@annotation(cn.ganlixin.annotation.TestAnnotation)")
public void one(TestAnnotation testAnonotation) {
System.out.println(testAnonotation.value());
System.out.println(testAnonotation.description());
}
}
上面的代码看似没有问题,one()方法中接收一个TestAnnotation的参数,以为能够获取到切点方法的注解信息,但是,IDE会告诉你如下错误:
2.4、创建Aspect的正确做法
package cn.ganlixin.aspect;
import cn.ganlixin.annotation.TestAnnotation;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class TestAspect {
// 先创建一个方法,方法名随意,但是需要制定@annotation为刚刚自定义的注解
@Pointcut("@annotation(cn.ganlixin.annotation.TestAnnotation)")
public void test() {}
// 使用@Before,需要先引入上面@Pointcut注解的方法名,在加上@annotation,
// @annotation中的值,需要和action方法中的参数名称相同(必须相同,但是名称任意)
@Before("test() && @annotation(testAnnotation)")
public void action(TestAnnotation testAnnotation) {
System.out.println("Annotation value : " + testAnnotation.value());
System.out.println("Annotation description : " + testAnnotation.description());
System.out.println("this is TestAspect.action()");
}
}
划重点:
// 第2个示例,强调@annotation中的值,需要和方法参数名相同
@Before("test() && @annotation(abcdef)")
public void action2(TestAnnotation abcdef) {
System.out.println("Annotation value : " + abcdef.value());
System.out.println("Annotation description : " + abcdef.description());
System.out.println("this is TestAspect.action()");
}
2.5、测试
Spring的配置类不用更改,测试代码如下:
package cn.ganlixin;
import cn.ganlixin.service.TestService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class AppTest {
@Test
public void testAOP2() {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
TestService testService = context.getBean(TestService.class);
testService.test1();
System.out.println("----------------------------");
testService.test2();
}
}
输出:
Annotation value : this is value
Annotation description : default description
this is TestAspect.action()
this is TestService.test1()
----------------------------
Annotation value : this is another value
Annotation description : this is description
this is TestAspect.action()
this is TestService.test2()
三、总结
要想是获取AOP中自定义注解的参数值,主要就一点: