Spring 自动装配多个服务实现

Spring autowire multiple service Implementations

我有一个基本接口和两个实现

public interface AnimalService
{
    public void eat();
}

@Service("animalService")
@Transactional
public class AnimalServiceImpl implements AnimalService
{
    @Override
    public void eat()
    {
        System.out.println("i'm eating");
    }
}

@Service("birdService")
@Transactional
public class BirdServiceImpl extends AnimalServiceImpl
{
    public void fly()
    {
        System.out.println("i'm flying");
    }
}

在我的主要方法中尝试以这种方式调用这两个服务实现:

public class test
{
    @Autowired
    private AnimalService animalService;
    @Autowired
    @Qualifier("birdService")
    private AnimalService birdService;

    public static void main(String[] args)
    {
        animalService.eat();
        birdService.eat();
        birdService.fly();
    }
}

这会产生编译错误,因为 birdService 找不到方法 fly()。然后我想也许原因是我自动装配 AnimalService 而不是 BirdServiceImpl,所以我将我的自动装配代码更改为:

   @Autowired
   @Qualifier("birdService")
   private AnimalService birdService;

更改为:

   @Autowired
   private BirdServiceImpl birdService;

但这会给我一个运行时间错误,也就是"can't find bean BirdServiceImpl"。 我有google 很多文档,有些说使用@Resource。但这对我不起作用。有人说在 Spring 上下文中注册 bean,而我所有的 bean 注册都是通过注释完成的。我不想触及 Spring 上下文。

现在我的解决方案是添加一个新接口

public interface BirdService extends AnimalService
{
    public void fly();
}

并让我的BirdServiceImpl实现这个接口

    public class BirdServiceImpl extends AnimalServiceImpl extends BirdService
    {
        public void fly()
        {
            System.out.println("i'm flying");
        }
    }

我的主要 class 更改为:

public class test
{
    @Autowired
    private AnimalService animalService;
    @Autowired
    private BirdService birdService;

    public static void main(String[] args)
    {
        animalService.eat();
        birdService.eat();
        birdService.fly();
    }
}

现在可以了。但对我来说,这并不完美。如果我使用普通的 java,我可以只编写单个接口和多个实现。在主要方法中,我可以选择要使用的实现。为什么在 spring 中,我必须为每个新实现构建一个新接口,以便让我的程序 运行.

我想知道我的场景是否有更好的方法?

正如我在您的问题中所读到的,您已经通过为继承的 class BirdService 创建 Interface 来解决问题。你抱怨只是因为你必须创建一个新的界面...

当我读到你的问题时,我又想到了另一个问题:你使用的是哪个 AOP?也许您必须将 CGLIB 添加到您的 class 路径(或 Maven POM 或 Gradle)。

阅读一些 Spring AOP documentation,我发现:

If the class of a target object that is to be proxied (hereafter simply referred to as the target class) doesn’t implement any interfaces, then a CGLIB-based proxy will be created. This is the easiest scenario, because JDK proxies are interface based, and no interfaces means JDK proxying isn’t even possible.

你的问题实际上暴露了两个问题:

1.继承问题

此问题与Spring框架无关,而是您对继承的误解所致。 如果您将服务声明为 AnimalService,显然您只能将其用作 AnimalService,而不管其实际实现如何。 如果你想使用具体的实现方法,你需要转换你的对象。

2。 'Autowiring a class' 问题

这通常应该在 Spring 中工作,所以如果您的代码不起作用取决于您的上下文配置。也许你也在你的应用程序中使用 AOP 或事务, 如果是,则启用自动代理生成器。这可能会导致您的问题。

看看这个问题:Spring Autowiring class vs. interface?。并注意:

When using autoproxies, you need to program to the interface, not the implementation

3。请注意

如何在 Java interface/class 名称的末尾使用 ()