@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.
An introduction is made using the @DeclareParents annotation. This annotation is used to declare that matching types have a new parent (hence the name). For example, given an interface UsageTracked, and an implementation of that interface DefaultUsageTracked, the following aspect declares that all implementors of service interfaces also implement the UsageTracked interface.
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 interface.
继续使用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(" cast to Printer "); ((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