我有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
的上述结果。请告诉我出了什么问题。
注意:以下答案假设
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 标识符名称,以使您的生活更轻松。
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 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);
}
}