Autowire.BY_NAME 类型参数的参数值不明确

问题描述 投票:0回答:2

我有2个班级,

A
B
B
取决于
A

这是课堂

A

package com.pm.spring;

public class A {

    public A() {
        System.out.println("Default Constructor in A");
    }
    
}

这是课堂

B

package com.pm.spring;

public class B {

    A a;

    public B(A a) {
        super();
        System.out.println("Parameterized Constructor in B");
        this.a = a;
    }
}

这是配置类

package com.pm.spring;

import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

    @Bean(name = "Bean-A")
    public A createA() {
        A a = new A();
        return a;
    }
    
    @Bean(name = "Bean-B", autowire = Autowire.BY_NAME)
    public B createB(A a) {
        B b = new B(a);
        return b;
    }
}

这是我初始化 Spring ApplicationContext 时的错误消息:

Default Constructor in A
Jan 08, 2025 12:52:58 PM org.springframework.context.support.AbstractApplicationContext refresh
WARNING: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'Bean-B' defined in com.pm.spring.AppConfig: Unsatisfied dependency expressed through method 'createB' parameter 0: Ambiguous argument values for parameter of type [com.pm.spring.A] - did you specify the correct bean references as arguments?
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'Bean-B' defined in com.pm.spring.AppConfig: Unsatisfied dependency expressed through method 'createB' parameter 0: Ambiguous argument values for parameter of type [com.pm.spring.A] - did you specify the correct bean references as arguments?
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:785)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:539)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1338)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:882)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:878)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550)
    at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:89)
    at com.pm.spring.Demo.main(Demo.java:10)

请帮助我理解为什么会出现此错误。

如果我删除

autowire = Autowire.BY_NAME
,它会正常运行。

package com.pm.spring;

import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

    @Bean(name = "Bean-A")
    public A createA() {
        A a = new A();
        return a;
    }
    
    @Bean(name = "Bean-B")
    public B createB(A a) {
        B b = new B(a);
        return b;
    }
}
Default Constructor in A
Parameterized Constructor in B

我期待包含

autowire = Autowire.BY_NAME
的上述结果。请告诉我出了什么问题。

java spring inversion-of-control
2个回答
2
投票

注意:以下答案假设

autowire = Autowire.BY_NAME
指的是被注入的bean,而不是对定义的bean的实际效果以及如何将其注入到其他地方。

声明

@Bean(name = "Bean-B", autowire = Autowire.BY_NAME)
public B createB(A a)

期望类型为

A
的 bean 被命名为
a
。但您指定了 bean 的名称为
Bean-A
。为了解决这个问题,您可以使用:

@Bean(name = "Bean-B", autowire = Autowire.BY_NAME)
public B createB(@Qualifier("Bean-A") A a)

指示

a
的 bean 名称应该是什么。

但是,我建议 bean 名称也应该是有效的 Java 标识符名称,以使您的生活更轻松。


1
投票

Spring 6 之前的配置

autowire
注释的
@Bean
属性应该用在要注入的依赖项的定义上,而不是用在客户端bean上。这里还有一个来自LogicBig的例子来展示它的用法。对于您的情况,您的代码应如下所示:

@Configuration
public class AppConfig {

    @Bean(name = "beanA", autowire = Autowire.BY_NAME)
    public A createA() {
        A a = new A();
        return a;
    }

    @Bean(name = "beanB")
    public B createB(A beanA) {
        B b = new B(beanA);
        return b;
    }
}

此外,如果您想要按名称进行实际自动装配,则

createB()
的参数名称应与
createA()
提供的 bean 名称相匹配。在你的情况下,自动装配无论如何都会发生,因为
A
只有一种定义,依靠类型自动装配。但是,如果您对
A
有多个 bean 定义,则自动装配将会失败,因为没有与
a
的参数
createB()
匹配的 bean。

@Configuration
public class AppConfig {

    @Bean(name = "beanA1", autowire = Autowire.BY_NAME)
    public A createA1() {
        return new A();
    }

    @Bean(name = "beanA2", autowire = Autowire.BY_NAME)
    public A createA2() {
        return new A();
    }

    // This definition would fail as there is no bean called a
    @Bean(name = "beanB")
    public B createB(A a) {
        return new B(a);
    }
}

Spring 6 配置

Spring 5.1
以来,
autowire
注释的@Bean属性已被弃用,并从Spring 6中完全删除。开发人员应优先使用
@Autowired
注释。

已弃用。从 5.1 开始,因为 @Bean 工厂方法参数解析和 @Autowired 处理取代了基于名称/类型的 bean 属性注入

在您的情况下,如果您想在 Spring 6 中通过名称实现自动装配,则需要使用

@Qualifier
@Resource
注解。你的代码看起来像这样:

@预选赛

@Configuration
public class AppConfig {

    @Bean(name = "beanA")
    public A createA() {
        return new A();
    }

    @Bean(name = "beanB")
    public B createB(@Qualifier("beanA") A a) {
        return new B(a);
    }
}

@资源

@Configuration
public class AppConfig {

    @Bean(name = "beanA")
    public A createA() {
        return new A();
    }

    @Bean(name = "beanB")
    @Resource(name = "beanA")
    public B createB(A a) {
        return new B(a);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.