1. 程式人生 > >Spring 實戰-第四章-4.3 Introductions&@DeclareParents

Spring 實戰-第四章-4.3 Introductions&@DeclareParents

frame 轉換 ret ger ted integer cati override pub

@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("\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