Java Spring 自动装配多服务实现

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28230570/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 05:49:19  来源:igfitidea点击:

Spring autowire multiple service Implementations

javaspringspring-mvc

提问by zzyclark

I have one base interface and two 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");
    }
}

In my main method try to call this two service implementation in this way:

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

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();
    }
}

This will give compilation error, since birdService can't find method fly(). Then I thought maybe the reason is i autowire AnimalService instead of BirdServiceImpl, So i change my autowire code from this:

这将导致编译错误,因为birdService 找不到方法fly()。然后我想可能是因为我自动装配 AnimalService 而不是 BirdServiceImpl,所以我改变了我的自动装配代码:

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

change to :

改成 :

   @Autowired
   private BirdServiceImpl birdService;

But this will give me a runtime error, which is "can't find bean BirdServiceImpl". I have google a lot of document, some say use @Resource. But this doesn't work for me. Some say register the bean in Spring Context, while all my bean registration is done by annotation. I don't want to touch Spring Context.

但这会给我一个运行时错误,即“找不到 bean BirdServiceImpl”。我谷歌了很多文档,有人说使用@Resource。但这对我不起作用。有人说在Spring Context中注册bean,而我所有的bean注册都是通过注解完成的。我不想碰 Spring Context。

Now My solution is to add a new interface

现在我的解决方案是添加一个新界面

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

And let my BirdServiceImpl to implement this interface

并让我的 BirdServiceImpl 来实现这个接口

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

And my main class change to this:

我的主要课程更改为:

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

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

Now is ok . But for me, this is not perfect. If I use plain java, i can just write single interface and multiple implementation. In the main method I can choose which implementation to use. Why in spring, i have to build a new interface for each new implementation in order to let my program run.

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

I want to know is there any better approach for my scenario?

我想知道我的场景有什么更好的方法吗?

采纳答案by davioooh

In your question you are actually exposing two issues:

在您的问题中,您实际上暴露了两个问题:

1. Inheritance issue

1.继承问题

This problem doesn't depends on Spring Framework, but is due by your misconception about inheritance. If you declare your service as AnimalService, you obviously can use it only as an AnimalService, regardless its real implementation. If you want to use concrete implementations methods, you need to cast your object.

这个问题不依赖于 Spring Framework,而是你对继承的误解造成的。如果您将服务声明为AnimalService,则显然只能将其用作AnimalService,而不管其实际实现。如果你想使用具体的实现方法,你需要转换你的对象。

2. 'Autowiring a class' issue

2.“自动装配类”问题

This should normally work in Spring, so if your code doesn't work depends on your context configuration. Maybe you are also using AOP or transactions in your app, If so, an autoproxy generator is enabled. This could cause your problem.

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

Take a look at this question: Spring Autowiring class vs. interface?. And note that:

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

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

使用自动代理时,您需要对接口进行编程,而不是对实现进行编程

3. Just a note

3. 只是一个注释

How can you use ()at the end of a Java interface/class name?

如何()在 Java 接口/类名的末尾使用?

回答by kazbeel

As I read in your question, you have already fixed the problem by creating an Interfacefor the inherited class BirdService. You only complain because you have to create a new Interface...

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

When I read your question, another question comes to mind: Which AOP are you using? Perhaps you have to add the CGLIB to your classpath (or Maven POM or Gradle).

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

Reading some of the Spring AOP documentation, I found this:

阅读一些 Spring AOP文档,我发现了这一点:

If the class of a targetobject 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.

如果要代理的目标对象的类(以下简称为目标类)未实现任何接口,则将创建基于 CGLIB 的代理。这是最简单的场景,因为 JDK 代理是基于接口的,没有接口意味着 JDK 代理甚至是不可能的。