Spring 4 - 自动装配泛型接口

5

从Spring v4.3.8开始,当Spring尝试加载依赖注入时,我遇到了一个问题。

我想根据T的类型(Debit1或Debit2)调用ManagerImpl1.java或ManagerImpl2.java实现中的“manage”方法。以下是详细信息:

原因: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.xxx.xxx.datacollection.infoprod.Manager' available: expected single matching bean but found 2: ManagerImpl1,ManagerImpl2

Business.java :

@Component
public class Business<T extends Debit> {

    @Autowired
    private Manager<T> manager;

    public void treatment(Context<T> context, FindServiceReturnMessage response) {

        manager.manage(response, context);
    }

Manager.java :

public interface Manager<T extends Debit> {

    void manage(final FindServiceReturnMessage response, Context<T> context);
}

ManagerImpl1.java :

@Component
public class ManagerImpl1 implements Manager<Debit1> {

    @Override
    public void manage(final FindServiceReturnMessage response, Context<Debit1> context) {

    }
}

ManagerImpl2.java :

@Component
public class ManagerImpl2 implements Manager<Debit2> {

    @Override
    public void manage(final FindServiceReturnMessage response, Context<Debit2> context) {

    }
}

此外,“Debit1”和“Debit2”实现了接口“Debit”。

我尝试了几种方法,但都没有成功...


1
泛型在运行时不存在,因此当它们用于“Autowired”对象时就没有意义。 如果您想要通过相同的接口注入多个bean,请查看“@Qualifier”注释。 - Dimitar Spasovski
@Dvorog:感谢您的回复。我理解了您所说的,并且已经尝试添加了@Qualifier注释,就像这样:@Autowired @Qualifier("ManagerImpl2") private Manager<T> manager;然而,这段代码将始终实现ManagerImpl2而不是ManagerImpl1。 - Clément
这就是重点。依赖项只在bean创建期间注入一次,初始化Spring上下文后不应更改其实现。您想如何决定要注入哪个bean? 如果您想根据某些业务逻辑获取bean,也许您应该查看ApplicationContext.getBean()方法。这种方法的问题是您不再使用IOC。 - Dimitar Spasovski
1个回答

1

您需要在Bean上添加一个限定符,如下所示:

@Component
@Qualifier("managerImpl2")
public class ManagerImpl2 implements Manager<Debit2> {

    @Override
    public void manage(final FindServiceReturnMessage response, Context<Debit2> context) 
    {

    }
}

然后,当您想要使用它时,请再次使用@Qualifier注释:

@Component
public class Business<T extends Debit> {

    @Autowired
    @Qualifier("managerImpl2")
    private Manager<T> manager;

    public void treatment(Context<T> context, FindServiceReturnMessage response) {

        manager.manage(response, context);
    }
}

然而,正如@dvorog在评论中所说,由于泛型在编译时不存在,您可能需要创建一个类似于以下的业务接口:

public interface Business<T extends Debit> {

    public void treatment(Context<T> context, FindServiceReturnMessage response);
}

并且实现BusinessImpl以便在有新的Debit种类时每次都可以指定它:

@Component
public class ManagerImpl2Business<Debit2> {

    @Autowired
    @Qualifier("managerImpl2")
    private Manager<Debit2> manager;

    public void treatment(Context<Debit2> context, FindServiceReturnMessage response) {

        manager.manage(response, context);
    }
}

这将重复一步操作,最终可能会导致一些难以维护的代码,或在某处使用 if (T instanceof Debit1) 使您的泛型生效。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接