通过在Java或Groovy代码中调用实现接口方法的类是如何被注入的?

huangapple go评论76阅读模式
英文:

How does class gets injected which implements interface method being called in Java or Groovy code?

问题

我有来自Spring框架项目的以下可工作的Groovy代码:

import org.springframework.oxm.Unmarshaller

public class ItemSearchService  {
    Unmarshaller unmarshaller;
    public ItemSearchResponse getObject(InputStream xml) {
    
        ItemSearchResponse its = null;
        try {
            its = (ItemSearchResponse) unmarshaller.unmarshal(new StreamSource(xml));
        } finally {
        }
        return its;
    }
}

Unmarshaller.unmarshall实际上是接口方法:
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/oxm/Unmarshaller.html

Unmarshaller接口由多个类实现。

是谁决定在运行时注入哪个实现类?它是如何决定使用哪个类的?

Spring IoC机制是否执行此操作?如果是这样,它是否在生成jar文件时选择一个特定的实现类,还是在运行时执行?

另外,如何知道它实际上使用了哪个实现类?

假设类路径中存在依赖的jar包,上述代码是否会在Spring之外的普通Java文件中工作?

英文:

I have below working groovy code from Spring framework project:

import org.springframework.oxm.Unmarshaller

public class ItemSearchService  {
    Unmarshaller unmarshaller;
    public ItemSearchResponse getObject(InputStream xml) {
    
	    ItemSearchResponse its = null;
        try {
            its = (ItemSearchResponse) unmarshaller.unmarshal(new StreamSource(xml));
        } finally {
        }
        return its;
    }
}

Unmarshaller.unmarshall is actually interface method:
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/oxm/Unmarshaller.html

Unmarshaller interface is implemented by several classes.

Who decides which implementing class to inject during runtime and how it decides which class to use?

Does Spring IoC mechanism does this? If so does it pick up one specific implementing class during build time when jar is generated or it does it during run time?

Also how to know which implementing class it actually used?

Will above code work outside of Spring in ordinary Java file assuming dependent jars in classpath?

答案1

得分: 5

关于Grails项目(而不是纯Spring项目),有一些事情需要澄清。

>在运行时谁决定注入哪个实现类,以及它如何决定使用哪个类?Spring IoC机制是否执行此操作?如果是这样,它是否在生成jar文件时在构建时选择一个特定的实现类,还是在运行时进行?

在纯Spring(Boot)中,Spring的操作在@svr的答案以及互联网上的其他文档中有很好的描述,但与您的情况关系不大。

在Grails中,使用惯例优于配置的原则,意味着:

  • 默认情况下,Bean自动装配是激活的
  • 只有声明为Grails工件(例如Service)的Bean会被自动注入。

通常情况下,如果您想要自动装配其他类型的Bean,您必须在某个地方声明它,否则Grails内部的Spring IoC容器根本找不到它。

您应该检查grails-app/conf/spring文件夹中的resources.groovy(根据版本可能是yaml或xml文件),查看是否在其中定义了unmarshaller Bean。它应该类似于:

beans = {
  unmarshaller Unmarshaller ....
}

所以,基本上,项目的所有jar文件中有多少个Unmarshaller接口的实现都无关紧要。唯一重要的是在您的resources.groovy中定义了什么。

如果您想要在运行时检查Bean的类,请在您的服务中记录它的类:

class ItemSearchService  {
  Unmarshaller unmarshaller
  ItemSearchResponse getObject(InputStream xml) {
     log.info "unmarshaller's class is $unmarshaller.class"
     // or
     // println "unmarshaller's class is $unmarshaller.class"
  }
}  
英文:

As soon as it goes about a Grails project (not a pure Spring one), some things should be clarified.

>Who decides which implementing class to inject during runtime and how it decides which class to use? Does Spring IoC mechanism does this? If so does it pick up one specific implementing class during build time when jar is generated or it does it during run time?

What Spring does in a plain Spring(Boot) is nicely described by @svr s answer and other documentation on the Internet, but has not much to do with your case.

In Grails the convention-over-configuration doctrine is used, meaning that

  • by default Bean Autowiring is active
  • only beans which are declared as Grails artefacts, like Service are auto-injected.

Usually, if you want to autowire a bean of other stereotype, you have to declare it somewhere, otherwise Spring IoC container inside Grails simply won't find it.

You shall check your grails-app/conf/spring folder for resources.groovy (or maybe yaml or xml files depending on version ) and see if your unmarshaller bean is defined there. It should look like:

beans = {
  unmarshaller Unmarshaller ....
}

So, basically it doesn't matter how many implementations of Unmarshaller interface are present in all project's jar files. The only thing what matters is what defined in your resources.groovy.

If you want to check the class of the bean in runtime, just log it's class in your service:

class ItemSearchService  {
  Unmarshaller unmarshaller
  ItemSearchResponse getObject(InputStream xml) {
     log.info "unmarshaller's class is $unmarshaller.class"
     // or
     // println "unmarshaller's class is $unmarshaller.class"
  }
}  

答案2

得分: 0

谁决定在运行时注入哪个实现类,以及它是如何决定使用哪个类?
Spring IoC 机制是否负责这个?如果是这样,它是在构建时选择一个特定的实现类(生成 JAR 包时)还是在运行时选择?

是的,Spring IOC 容器。这是在应用程序运行时发生的。

另外,如何知道它实际上使用了哪个实现类?

在大多数情况下,您需要定义具有实现的 bean 来选择。在其他情况下,您可以查看 Spring 自动配置类。

上述代码在不使用 Spring 的情况下是否可以在普通 Java 文件中工作,假设依赖的 JAR 在类路径中?

不确定您在"不使用 Spring"方面的意思,但只要应用程序被正确打包,应该都能正常工作。

快速概述

Spring IOC 仅在应用程序上下文中找到 bean 时才会注入一个 bean。应用程序上下文在很松的意义上是 bean 的存储库。

类路径扫描和注册

Spring 扫描应用程序以获取所有带有注解的类,并在应用程序上下文中注册 bean 定义。带有注解的类包括 @Component、@Repository、@Service、@Controller、@Configuration。更多信息

依赖注入

Spring DI 创建 bean,并将它们作为依赖项注入到应用程序中。您可以使用注册的 bean 在不同的应用程序组件之间创建依赖关系,Spring 将自动为您进行自动连接。更多信息。有两种类型的 DI - 基于构造函数的和基于 setter 的 - 构造函数用于必需的依赖关系,基于 setter 的用于可选的依赖关系。更多信息

当您使用任何 Spring 类时,都会提供合理的默认值。您只需在没有默认值的情况下或者希望选择不同实现时定义 bean。应用程序上下文可以通过使用 Spring Boot 自动配置进一步丰富,其中所有相关类都被连接在一起形成一个连贯的入口类。然后,您可以轻松地将这些注入到应用程序中以开始使用。更多信息

示例

您可以在 Web 服务模块的 @Configuration 类中定义 bean。

@Configuration
public class WSConfig {
   @Bean
   public Jaxb2Marshaller marshaller() {
      Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
      marshaller.setContextPath("某个包");
   }

   @Bean
   public WebServiceTemplate webServiceTemplate(Jaxb2Marshaller marshaller) {         
      WebServiceTemplate webServiceTemplate = new WebServiceTemplate(marshaller);
   }
}

@RequiredArgsConstructor
public class ItemSearchService {
    private final Unmarshaller unmarshaller;
    public ItemSearchResponse getObject(InputStream xml) {
       ItemSearchResponse its = null;
       try {
        its = (ItemSearchResponse) unmarshaller.unmarshal(new StreamSource(xml));
        } finally {}
       return its;
    }
}

使用 Spring Boot 时,类似的配置由 WebServicesAutoConfiguration 自动处理,可在使用 Spring Boot 时进行自定义配置。

英文:

> Who decides which implementing class to inject during runtime and how
> it decides which class to use?
> Does Spring IoC mechanism does this? If so does it pick up one
> specific implementing class during build time when jar is generated or
> it does it during run time?

Yes Spring IOC container. It happens at run time when the application is run.

> Also how to know which implementing class it actually used?

For most part you will have to define bean with implementation to pick. For other cases you can look at the spring auto configuration classes.

> Will above code work outside of Spring in ordinary Java file assuming
> dependent jars in classpath?

Not sure what you mean outside of Spring but as long as application is packaged correctly it should all work.

Quick Overview

Spring IOC will only inject a bean when found in the application context. An application context loosely is repository of beans.

Classpath Scanning and Registration

Spring scans application to pick up all the stereotyped classes and registers bean definition with application context. Stereotyped annotations include @Component, @Repository, @Service, @Controller, @Configuration. More

Dependency Injection

Spring DI creates the bean and injects them as dependencies into application. You can create dependencies between different application components using the registered beans and spring will autowire these for you. More. There are two types of DI - Constructor based and setter based - Constructor for required dependencies and setter based for optional dependencies. More

There are sensible defaults provided when you use any spring classes. You just have to define the bean where there is no default or you would like to pick different implementation. Application context can be further be enriched by using Spring Boot Auto Configuration where all related classes are wired together to form a coherent entry classes. You can then easily inject these into application for getting started. More

Example

You can define bean in the @Configuration class for a web service module.

@Configuration
public class WSConfig {
   @Bean
   public Jaxb2Marshaller marshaller() {
      Jaxb2Marshaller marsharller = new Jaxb2Marshaller();
      marsharller.setContextPath("some package");
   }

   @Bean
   public WebServiceTemplate webServiceTemplate(Jaxb2Marshaller marsharller) {         
      WebServiceTemplate webServiceTemplate = new WebServiceTemplate(marsharller);
   }
}

@RequiredArgsConstructur
public class ItemSearchService  {
    private final Unmarshaller unmarshaller;
    public ItemSearchResponse getObject(InputStream xml) {
       ItemSearchResponse its = null;
       try {
        its = (ItemSearchResponse) unmarshaller.unmarshal(new StreamSource(xml));
        } finally {}
       return its;
    }
 }

This similar configuration is automatically taken care by WebServicesAutoConfiguration with ways to customize when using Spring Boot.

huangapple
  • 本文由 发表于 2020年10月25日 00:14:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/64515471.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定