自动装配是如何决定使用哪个上下文/配置文件的。

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

How is autowired deciding which context/configuration file to use

问题

Scenario: Spring Mvc应用程序使用xml配置文件(自动扫描和设置mvc dispatcher - 标准配置)。还有一个Java配置文件(在自动扫描的包内),里面有一个bean,我们称之为A。然后我们有一个使用@autowired注解来注入bean A,然后在控制器内以某种方式使用此对象的RestController。

Question: @Autowired注解如何知道在Java注解配置文件中查找bean的位置?
如果我的理解正确,控制器中用于@Autowired的上下文应该是从xml文件创建的,并且包括所有自动扫描的类(用@Component注解标注) - 那么这是如何工作的,它如何从Java配置文件中访问bean呢?

英文:

Scenario: Spring Mvc application with xml configuration file (auto scanning and setting mvc dispatcher - standard config). Also there is Java configuration file (within autoscanned package) with one bean, let's call it A. Then we have RestController which uses @autowired annotation to inject bean A and then use this object iside the controller in some way.

Question: How does autowired annotation knows where to look for bean in java annotated configuration file?
If my understanding is correct, the context that is being used for autowired in the controller should be created from xml file and all autoscanned classes (anotated with Component) - so how does this work and how does it access bean from java configuration file?

答案1

得分: 1

来自 @Configuration 的 Javadoc:

@Target(value=TYPE)
@Retention(value=RUNTIME)
@Documented
@Component
public @interface Configuration

表明一个类声明了一个或多个 @Bean 方法,并且可能会被 Spring 容器处理,以在运行时为这些 bean 生成 bean 定义和服务请求。

因此,当您的 @Configuration 类位于使用 <context:component-scan/> 在您的 XML 配置中定义的 base-packages 之一时,它将被扫描为一个 @Component

如果您希望 @Configuration 类在没有 XML 配置的情况下工作,您需要使用 AnnotationConfigApplicationContext 初始化上下文。

示例 web.xml

<web-app>
    <context-param>
        <param-name>contextClass</param-name>
        <param-value>
            org.springframework.web.context.support.AnnotationConfigWebApplicationContext
        </param-value>
    </context-param>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>com.acme.AppConfig</param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!-- 像往常一样声明一个 Spring MVC DispatcherServlet -->
    <servlet>
        <!-- 配置在此处 -->
    </servlet>

    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
</web-app>

注意:

来自 Spring Framework 参考文档

注解注入在 XML 注入之前执行。因此,XML 配置会覆盖通过这两种方法连接的属性的注解。

更多阅读:

英文:

From javadoc of @Configuration:

> lang-java
&gt; @Target(value=TYPE)
&gt; @Retention(value=RUNTIME)
&gt; @Documented
&gt; @Component
&gt; public @interface Configuration
&gt;

>
Indicates that a class declares one or
> more @Bean methods and may be processed by the Spring container to
> generate bean definitions and service requests for those beans at
> runtime.

So your @Configuration class will be scanned as a @Component when it is in one of the base-packages defined with &lt;context:component-scan/&gt; in your XML configuration.

If you want the @Configuration class to work without XML configuration, you need to initialize the context using AnnotationConfigApplicationContext.

Example web.xml:

&lt;web-app&gt;
    &lt;context-param&gt;
        &lt;param-name&gt;contextClass&lt;/param-name&gt;
        &lt;param-value&gt;
            org.springframework.web.context.support.AnnotationConfigWebApplicationContext
        &lt;/param-value&gt;
    &lt;/context-param&gt;

    &lt;context-param&gt;
        &lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;
        &lt;param-value&gt;com.acme.AppConfig&lt;/param-value&gt;
    &lt;/context-param&gt;

    &lt;listener&gt;
        &lt;listener-class&gt;org.springframework.web.context.ContextLoaderListener&lt;/listener-class&gt;
    &lt;/listener&gt;

    &lt;!-- Declare a Spring MVC DispatcherServlet as usual --&gt;
    &lt;servlet&gt;
        &lt;!-- Configuration goes here --&gt;
    &lt;/servlet&gt;

    &lt;servlet-mapping&gt;
        &lt;servlet-name&gt;dispatcher&lt;/servlet-name&gt;
        &lt;url-pattern&gt;/*&lt;/url-pattern&gt;
    &lt;/servlet-mapping&gt;
&lt;/web-app&gt;

<br/>
Note:

From Spring Framework Reference:

> Annotation injection is performed before XML injection. Thus, the XML
> configuration overrides the annotations for properties wired through
> both approaches.

<br/>
Further Reading:

答案2

得分: 0

这是按需进行的Bean注入。

Spring会寻找所有的配置类,从这些类开始扫描包和XML文件以创建Bean。

在扫描过程中,如果发现需要创建特定的Bean,它将尝试创建该Bean,创建过程中可能会遇到该Bean依赖于其他Bean,此时它将尝试创建其他依赖Bean。一旦依赖的Bean被创建,它们可以通过字段注入或构造函数注入进行自动装配。在创建过程中还需要考虑“延迟加载”和“可选”Bean。Spring按照需要遵循Bean创建路径,如果在扫描器中提供了包名,这可能会导致循环引用。

对于XML,情况变得更加复杂,例如,一个XML Bean可能依赖于基于包扫描器的Bean,反之亦然,那么Spring必须遍历每个XML文件,以确定如何创建该Bean。

英文:

It's on-demand bean injection.

Spring looks for all the configuration classes, from these classes it starts scanning packages and XML files to create beans.

While scanning if it founds that a particular bean has to be created then it will try to create that bean, while creating it may encounter that this bean is depending on other beans, now it will try to create other dependents beans. Once dependent beans are created they can now be autowired either using Field injection or construction injection. While creating it needs to also consider lazy and optional beans. Spring follows the bean creation path as they require, if you give package name in the scanner then this can create a cycle as well.

For XML things become more complex, for example, a XML bean might be depending on package scanner based and vice-versa then spring has to go through each XML file to see how to create that bean.

huangapple
  • 本文由 发表于 2020年6月5日 21:32:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/62216530.html
匿名

发表评论

匿名网友

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

确定