Spring Constructor @Autowired и @Qualifier терпит неудачу

Упрощенный код (я использую Spring 3.1.4).

Вот класс, который я хочу автоматически подключить:

public class MyCoolClass {

    @Autowired
    public MyCoolClass(
        @Qualifier("CoolBean1") SomeOtherClass1 foo1,
        @Qualifier("CoolBean2") SomeOtherClass1 foo2
    ) {
        this.foo1 = foo1;
        this.foo2 = foo2;
    }

    // ...
}

Вот мой весенний конфиг xml:

<bean name="CoolBean1" class="mypackage.SomeOtherClass1"/>
<bean name="CoolBean2" class="mypackage.SomeOtherClass1"/>
<bean name="GreatBean" class="mypackage.MyCoolClass"/>

И вот как я пытаюсь получить боб:

GenericApplicationContext ctx = new GenericApplicationContext();
XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(ctx);
xmlReader.loadBeanDefinitions(new ClassPathResource("config.xml"));
ctx.refresh();

В момент вызова обновления я сталкиваюсь с этим:

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'GreatBean' defined in class path resource [config.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [mypackage.MyCoolClass]: No default constructor found; nested exception is java.lang.NoSuchMethodException: mypackage.MyCoolClass.<init>()
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:997)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:943)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:485)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
        at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:607)
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:925)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:472)
        at mypackage.Runner.main(Runner.java:234)

Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [mypackage.MyCoolClass: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.amazon.maxis.security.gbac.AsynchronousFolderAuthorizationManager.<init>()
        at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:83)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:990)
        ... 11 more

Caused by: java.lang.NoSuchMethodException: mypackage.MyCoolClass.<init>()
        at java.lang.Class.getConstructor0(Class.java:2800)
        at java.lang.Class.getDeclaredConstructor(Class.java:2043)
        at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:78)
        ... 12 more

Вопросы:

  • Зачем мне конструктор по умолчанию? Я бы не хотел, чтобы это называлось.
  • Нужен ли мне по какой-то причине «@Component» в классе? Я вижу, что другие делают это
  • Почему этот код работает (насколько я могу судить) через мои тесты junit? (Как я их запускаю, показано ниже.

Вот фрагмент для запуска модульных тестов:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:config.xml"})
public class MyJunitTest {
    //...
}

person Cory Kendall    schedule 18.07.2013    source источник
comment
У вас есть пустой конструктор?   -  person Martin Spa    schedule 19.07.2013
comment
@MartinSpa Нет, не знаю. Я также не хочу его реализовывать.   -  person Cory Kendall    schedule 19.07.2013
comment
На самом деле, может быть, вам и не нужно. Просто при определении bean-компонентов в xml используйте аргумент-конструктора также для параметров в вашем конструкторе, stackoverflow.com/a/10649348/ 228692   -  person Martin Spa    schedule 19.07.2013
comment
@MartinSpa Я бы хотел избежать этого и вместо этого использовать Autowiring.   -  person Cory Kendall    schedule 19.07.2013
comment
Я обновил свой ответ, дайте мне знать, если это сработает   -  person Cristian Meneses    schedule 19.07.2013


Ответы (2)


Поскольку у вас нет пустого конструктора, вы должны указать аргументы конструктора, чтобы разрешение конструктора Spring работало...

Например

package examples;

public class ExampleBean {

    private int years;             //No. of years to the calculate the Ultimate Answer
    private String ultimateAnswer; //The Answer to Life, the Universe, and Everything

    public ExampleBean(int years, String ultimateAnswer) {
        this.years = years;
        this.ultimateAnswer = ultimateAnswer;
    }
}

вы можете явно указать аргументы, определив bean-компонент следующим образом

<bean id="exampleBean" class="examples.ExampleBean">
  <constructor-arg type="int"><value>7500000</value></constructor-arg>
  <constructor-arg type="java.lang.String"><value>42</value></constructor-arg>
</bean> 

----------------------------- ОБНОВИТЬ -------------------- ------------

Если вы хотите избежать добавления аргументов-конструкторов вручную, вы можете попробовать их автоматически связать с помощью

<bean name="GreatBean" class="mypackage.MyCoolClass" autowire="constructor" />
person Cristian Meneses    schedule 18.07.2013

Ответ (через несколько часов) заключается в использовании:

AnnotationConfigUtils.registerAnnotationConfigProcessors(ctx);

После прочтения определений bean-компонентов, но до первого обновления контекста. Это дает мне то, что я хочу (автоматическое подключение конструктора), не касаясь ни моего XML, ни моих определений классов. Он также будет хорошо масштабироваться (в будущем я могу продолжать писать XML и классы, как указано выше, и мне не нужно ничего менять. Последний бит кода, который работал, был:

GenericApplicationContext ctx = new GenericApplicationContext();
XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(ctx);
xmlReader.loadBeanDefinitions(new ClassPathResource("config.xml"));
AnnotationConfigUtils.registerAnnotationConfigProcessors(ctx);
ctx.refresh();
person Cory Kendall    schedule 19.07.2013
comment
Отлично, вы также можете добиться этого, добавив <context:annotation-config/> в свой файл конфигурации. - person Biju Kunjummen; 19.07.2013