筆記9 AOP練習3(通過註解引入新功能 )
切面可以為Spring bean添加新方法。 在Spring中,切面只是實現了它們所包裝bean相同接口的 代理。如果除了實現這些接口,代理也能暴露新接口的話,會怎麽樣 呢?那樣的話,切面所通知的bean看起來像是實現了新的接口,即便 底層實現類並沒有實現這些接口也無所謂。
使用Spring AOP,我們可以為bean引入新的方法。 代理攔截調用並委托給實現該方法的其他對象
需要註意的是,當引入接口的方法被調用時,代理會把此調用委 托給實現了新接口的某個其他對象。實際上,一個bean的實現被拆分 到了多個類中。
場景描述:
在一場音樂會中,添加川劇變臉的環節,但在原來的古典音樂表演類(Classcial.java)中沒有這個方法,所以需要為這個表演類再新加一個方法。
1.創建一個新的接口Encoreable.java
1 package concert2; 2 3 public interface Encoreable { 4 void performEncore(); 5 }
2.實現這個接口DefaultEncoreable.java
1 package concert2; 2 3 public class DefaultEncoreable implements Encoreable { 4 5 @Override 6 public void performEncore() { 7 //TODO Auto-generated method stub 8 System.out.println("川劇變臉"); 9 } 10 11 }
3.創建一個用於註入新方法的切面EncoreableIntroducer.java
1 package concert2; 2 3 import org.aspectj.lang.annotation.Aspect; 4 import org.aspectj.lang.annotation.DeclareParents; 5 import org.springframework.stereotype.Component;6 7 @Aspect 8 @Component 9 public class EncoreableIntroducer { 10 @DeclareParents(value = "concert2.Performance+", defaultImpl = DefaultEncoreable.class) 11 public static Encoreable encoreable; 12 }
EncoreableIntroducer是一個切面,同時聲明它是一個bean。但是,它與我們 之前所創建的切面不同,它並沒有提供前置、後置或環繞通知,而是 通過@DeclareParents註解,將Encoreable接口引入 到Performance bean中。 @DeclareParents註解由三部分組成:
- value屬性指定了哪種類型的bean要引入該接口。在本例中,也 就是所有實現Performance的類型。(標記符後面的加號表示 是Performance的所有子類型,而不是Performance本 身。)
- defaultImpl屬性指定了為引入功能提供實現的類。在這裏, 我們指定的是DefaultEncoreable提供實現。
- @DeclareParents註解所標註的靜態屬性指明了要引入了接 口。在這裏,我們所引入的是Encoreable接口。
而且在將EncoreableIntroducer聲明為一個bean後,Encoreable也就成為了一個bean。
3.采用java裝配bean ConcertConfig.java
1 package concert2; 2 3 import org.springframework.context.annotation.ComponentScan; 4 import org.springframework.context.annotation.Configuration; 5 import org.springframework.context.annotation.EnableAspectJAutoProxy; 6 7 @Configuration 8 @EnableAspectJAutoProxy // 啟用AspectJ自動代理 9 @ComponentScan 10 public class ConcertConfig { 11 12 }
4.測試
在此做了對比,因為Encoreable已經聲明為bean,所以也可以直接加載,然後調用其方法。其次,因為Encoreable的方法已經添加到Performance中,所以也可以通過Performance的對象進行調用,但需要註意的是,在調用新加入的方法時要進行“偽裝”,即將Performance的對象強制轉換為Encoreable,然後再調用新加入的方法,以逃過編譯器的檢查。如果不進行引入的話,強行改變Performance對象的類型,然後調用“新方法”,則會報錯。
1 package concert2; 2 3 import org.junit.Test; 4 import org.junit.runner.RunWith; 5 import org.springframework.beans.factory.annotation.Autowired; 6 import org.springframework.test.context.ContextConfiguration; 7 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 8 9 @RunWith(SpringJUnit4ClassRunner.class) 10 @ContextConfiguration(classes = concert.ConcertConfig.class) 11 public class ConcertTest { 12 @Autowired 13 public Performance p; 14 @Autowired 15 public Encoreable en; 16 @Test 17 public void test() { 18 p.perform(); 19 System.out.println("-----------------------------"); 20 System.out.println("自己創建對象調用"); 21 en.performEncore(); 22 System.out.println("-----------------------------"); 23 System.out.println("通過Performance對象調用“新方法”"); 24 Encoreable e = (Encoreable) p; 25 e.performEncore(); 26 } 27 }
5.結果
省略的部分請參照筆記7
筆記9 AOP練習3(通過註解引入新功能 )