Spring 实战-第四章-4.3 Introductions&@DeclareParents

Posted Lv Jianwei

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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.
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的主要内容,如果未能解决你的问题,请参考以下文章

Spring 实战-第四章-4.4 使用xml中声明切面及引入新方法

报错spring实战(第四版)示例代码 ,使用 @DeclareParents 实现aop出错

spring实战第四版第五章pom.xml

阅读笔记《Java EE企业应用实战》(第四版)第七章——Spring的基本用法

《树莓派项目实战》第四节 用LED点阵显示爱心

《Python多人游戏项目实战》第四节 实现房间功能