繁体   English   中英

Spring - 自动装配通用接口的通用实现

[英]Spring - autowiring generic implementation of generic interface

我有一个小问题。 这可能是微不足道的,但我以前从未面对过它。

我有通用接口和它的通用实现。 我想自动装配它,但发生了错误。 以下是详细信息:

接口

@Service
public interface Serializing<T extends Serializable> {
    String serialize(T toBeSerialized);

    T deserialize(String toBeDeserialized, Class<T> resultType);
}

履行

@Service
public class JsonSerializer<T extends Serializable> implements Serializing<T> {
   /** code **/
}

自动尝试

private NoteDAO noteDAO;

@Qualifier("jsonSerializer")
private Serializing<UserComment> serializer;

@Autowired
public NoteController(NoteDAO noteDAO, Serializing<UserComment> serializer) {
    this.noteDAO = noteDAO;
    this.serializer = serializer;
}

错误

Parameter 1 of constructor in somepackagepath.NoteController required a bean of type 'anotherpackagepath.Serializing' that could not be found.

我想尽量保持简单。 我已经检查了网络,但我发现只是在配置中定义我的确切bean。 如果可能的话,我宁愿避免它。

您的特定情况下 ,Spring不允许使用泛型类型作为依赖项连接,例如:

@Autowired
public NoteController(NoteDAO noteDAO, Serializing<UserComment> serializer) {
    this.noteDAO = noteDAO;
    this.serializer = serializer;
}

原因很简单:一致性。
您使用@Service创建Spring bean的依赖关系:

@Service
public class JsonSerializer<T extends Serializable> implements Serializing<T> {
   /** code **/
}

可以连接到其他bean。

试想一下,依赖于豆类Serializing的实例不使用相同的通用: Serializing<UserComment>FooSerializing<UserQuestion>Bar如:

public class Foo{

    @Autowired
    public Foo(NoteDAO noteDAO, Serializing<UserComment> serializer) {
        this.noteDAO = noteDAO;
        this.serializer = serializer;
    }

}
public class Bar{

    @Autowired
    public Bar(NoteDAO noteDAO, Serializing<UserQuestion> serializer) {
        this.noteDAO = noteDAO;
        this.serializer = serializer;
    }

}

这里的Serializing对象是相同的,但每个bean声明一个不同的泛型。
因此它会打破泛型类型的类型安全性。


事实上,由于Spring(从Spring 4开始)拥有一个能够解析类型的Resolver ,因此擦除泛型并不是真正的问题:

在幕后,新的ResolvableType类提供了实际使用泛型类型的逻辑。 您可以自己使用它来轻松导航和解析类型信息。 ResolvableType上的大多数方法本身都会返回ResolvableType

在Spring 4之前,您还有其他解决方法来接受bean依赖项中的泛型类型。
真正的问题是你用@Service注释了一个泛型类,使它成为一个bean,而它是一个必须配置为bean的泛型类的实例。

因此,要实现您想要执行的操作,请声明要在@Configuration类中实例化的JsonSerializer bean:

@Configuration
public class SerializingBeans {

    @Bean
    public JsonSerializer<UserComment> userCommentSerializer() {
        return new JsonSerializer<UserComment>();
    }

    @Bean
    public JsonSerializer<UserAnswer> userAnswerSerializer() {
        return new JsonSerializer<UserAnswer>();
    }
}

您现在可以将依赖项连接为泛型类型:

@Service
public class NoteController {

    private Serializing<UserComment> userCommentSerializer;

    @Autowired
    public NoteController(Serializing<UserComment> serializer) {
        this.userCommentSerializer = serializer;

    }
}

它与java的类型擦除有关: https//docs.oracle.com/javase/tutorial/java/generics/erasure.html

在java中,您无法在运行时知道泛型类型。 唯一的工作原理是使用匿名类或非泛型类的继承类: 使用spring注入匿名类

您必须告诉Spring您希望它自动装配的所有bean。 没有例外。

如果你不能事先拼出来,那么我会说它不是注射的候选人。

有些事情你需要完全掌控并打电话给new 也许你的情况就是其中之一。 这没有错; 它只是意味着Spring DI不适合该用例。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM