Spring 實戰-第四章-4.3 Introductions&@DeclareParents
@DeclareParents非常有意思,單獨拿出來,這個可以給實現相同接口的類增加新的共同接口,
這樣在不侵入原有代碼的情況下,轉換成其他類型並擁有新的方法。
這個功能在Spring AOP文檔中叫做Introductions:
Introductions (known as inter-type declarations in AspectJ) enable an aspect to declare that advised objects implement a given interface, and to provide an implementation of that interface on behalf of those objects.
The interface to be implemented is determined by the type of the annotated field. The value attribute of the @DeclareParents annotation is an AspectJ type pattern :- any bean of a matching type will implement the UsageTracked interface. Note that in the before advice of the above example, service beans can be directly used as implementations of the UsageTracked
繼續使用CompactDisc和其實現BlankDisc
CompactDisc
package main.java.soundsystem; public interface CompactDisc { void play(); void playTrack(Integer trackNumber); }
BlankDisc
package main.java.soundsystem; import java.util.List; public class BlankDisc implements CompactDisc{ private String title; private String artist; private List<String> tracks; public BlankDisc setTitle(String title) { this.title = title; return this; } public BlankDisc setArtist(String artist) { this.artist = artist; return this; } public String getTitle() { return title; } public String getArtist() { return artist; } public void setTracks(List<String> tracks) { this.tracks = tracks; } public void play() { System.out.println("Playing " + title + " by " + artist); if(tracks!=null) { for (String track : tracks) { System.out.println("-Track: " + track); } } } @Override public void playTrack(Integer trackNumber) { System.out.println("Playing "+tracks.get(trackNumber-1)); } }
定義一個新的Printer接口及其實現CDPrinter
package main.java.soundsystem; public interface Printer { void printCover(); }
package main.java.soundsystem; public class CDPrinter implements Printer { @Override public void printCover() { System.out.println("print CD cover..."+Time); } public String getTime() { return Time; } public CDPrinter setTime(String time) { Time = time; return this; } private String Time; }
那麽如何在不修改CompactDisc及其實現的情況下,增加新的方法呢?使用@DeclareParent,使用Java代碼配置。
@DeclareParents有兩個參數value,defaultImpl,
value表示要為哪些類增加新的父類接口,最後的“+”表示對所有實現CompactDisc接口的類增加接口,
defaultImpl表示新增接口的默認實現,這裏新增接口就是被增加標簽的Printer接口,
這樣所有實現CompactDisc接口的類,都引入了Printer接口,並且擁有了Printer中的方法。
package main.java.soundsystem; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.DeclareParents; import org.springframework.stereotype.Component; @Component @Aspect public class CDPrinterAspect { @DeclareParents(value = "main.java.soundsystem.CompactDisc+",defaultImpl =CDPrinter.class) public static Printer printer; }
增加xml配置,註意配置中並沒有聲明Printer對應的Bean。
<?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:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="main.java.soundsystem"/> <aop:aspectj-autoproxy/> <bean id="blankDisc" class="main.java.soundsystem.BlankDisc"> <property name="title" value="Sgt. Pepper‘s Lonely Heart Club Band"/> <property name="artist" value="the Beatles"/> <property name="tracks"> <list> <value>Sgt. Pepper‘s Lonely Hearts Club Band</value> <value>With a Little Help from My Friends</value> <value>Lucy in the Sky with Diamonds</value> <value>Getting Better</value> <value>Fixing a Hole</value> </list> </property> </bean> </beans>
具體使用,通過上下文使用BlankDisc生成了了一個CompactDisc的實例,然後顯式轉換為Printer對象,並且使用其中由CDPrinter實現的方法,
package main.java.soundsystem; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class main { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("TrackCounterConfig.xml"); CompactDisc cd=(CompactDisc)context.getBean("blankDisc"); cd.play(); System.out.println("\ncast to Printer\n"); ((Printer)cd).printCover(); } }
結果:
Playing Sgt. Pepper‘s Lonely Heart Club Band by the Beatles -Track: Sgt. Pepper‘s Lonely Hearts Club Band -Track: With a Little Help from My Friends -Track: Lucy in the Sky with Diamonds -Track: Getting Better -Track: Fixing a Hole cast to Printer print CD cover...null
Spring 實戰-第四章-4.3 Introductions&@DeclareParents