目錄
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)
1
2
3
4
5
6
7
8
9
10
11
12
|
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中:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
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,增加業務邏輯
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
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配置類
主要做的是:指定包掃描路徑
1
2
3
4
5
6
7
8
9
10
11
12
|
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、測試
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
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();
}
}
|
輸出:
1
2
|
this
is before output message
this
is DemoService.demo()
|
二、獲取自定義注解的參數
2.1、創建帶屬性的自定義注解
要獲取自定義注解參數,就需要在自定義注解中增加幾個屬性,下面自定義的TestAnnotation中有兩個屬性:value和description。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
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中有兩個方法,分別使用了自定義注解:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
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來實現的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
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的正確做法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
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()"
);
}
}
|
划重點:
1
2
3
4
5
6
7
|
// 第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的配置類不用更改,測試代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
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();
}
}
|
輸出:
1
2
3
4
5
6
7
8
9
|
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中自定義注解的參數值,主要就一點: