1、利用註解實現AOP的基本流程java
1.一、建立一個註解,用來註解切點(pointcut)spring
1.二、建立一個service,使用上面定義的註解來指定切點測試
1.三、建立Aspect,增長業務邏輯this
1.四、建立Spring配置類spa
1.五、測試blog
2、獲取自定義註解的參數接口
2.一、建立帶屬性的自定義註解ip
2.二、建立service使用帶屬性的自定義註解get
2.三、建立Aspect的錯誤示例博客
2.四、建立Aspect的正確作法
2.五、測試
3、總結
若是特別熟悉自定義註解實現AOP,能夠直接轉到第二部分:跳轉。
Spring中,能夠經過自定義註解的方式來實現AOP,比較簡單,流程以下:
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 { //注意這裏沒有定義屬性 }
這裏爲了節約篇幅,就不建立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()"); } }
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"); } }
主要作的是:指定包掃描路徑
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 { }
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()
要獲取自定義註解參數,就須要在自定義註解中增長几個屬性,下面自定義的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"; }
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()"); } }
在寫博客以前,我也搜過相關的博客,可是發現不少博客中寫的都是利用@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會告訴你以下錯誤:
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()"); }
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中自定義註解的參數值,主要就一點: