Spring аннотации - @Configuration для запуска автосборки Spring bean

Если я объявлю класс с помощью @Bean, а затем просканирую компонент для класса, Spring создаст экземпляр класса, вызвав его конструктор и внедрив аргументы конструктора, а также внедрив любые поля, отмеченные @Inject. Для простоты назовем эту весну автостроительством.

Мне не нравится сканирование компонентов, и я хочу полностью его избежать (я не хочу обсуждать причины, по которым мне это не нравится). Вместо этого я хотел бы использовать объект @Configuration, но все же хотел бы, чтобы мне были доступны функции автоматического построения. Можно ли вызвать Spring для автоматической сборки моих объектов вместо того, чтобы явно передавать все аргументы конструктора в мой объект @Configuration?

Предположим, что у меня есть bean:

public class MyServiceImpl implements MyService {
    public MyServiceImpl(Dependency1 d1, Dependency d2) { ... }
    ....
}

Я мог бы определить объект конфигурации следующим образом:

@Configuration
public class MyConfiguration {
    // lets assume d1 and d2 are defined in another @Configuration
    @Inject
    Dependency1 d1; 

    @Inject
    Dependency2 d2;

    @Bean
    public MyService myService() { 
        // I dislike how I have to explicitly call the constructor here
        return new MyServiceImpl(d1, d2);
    }
}

Но теперь мне пришлось явно вызывать конструктор MyServiceImpl самостоятельно, поэтому мне придется постоянно обновлять его по мере изменения моего конструктора с течением времени.

Я надеялся, что смогу объявить абстрактный метод, чтобы можно было выполнить весеннее автоматическое построение:

@Configuration
public abstract class MyConfiguration {
    @Bean
    public abstract MyServiceImpl myService();
}

Но это не работает. Есть ли способ, которым я могу вызвать весеннее автоматическое построение без использования сканирования компонентов?

В Google Guice это можно сделать с помощью Binder: https://google-guice.googlecode.com/svn/trunk/javadoc/com/google/inject/Binder.html

В Tapestry IOC это можно сделать с помощью ServiceBinder: http://tapestry.apache.org/ioc-cookbook-basic-services-and-injection.html#IoCCookbook-BasicServicesandInjection-SimpleServices

Обновить

Основываясь на ответе спода, я смог добиться того, к чему стремился (спасибо!). Тестовый пример включен для всех, кто хочет сделать то же самое:

import java.util.Date;
import javax.inject.Inject;
import junit.framework.Assert;
import org.junit.Test;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

public class AutoBuildConfigurationTest {
    @Configuration
    public static class MyConfiguration {
        @Inject
        private AutowireCapableBeanFactory beanFactory;

        @Bean
        public Date date() {
            return new Date(12345);
        }

        @Bean
        public MyService myService() {
            return autoBuild(MyService.class);
        }

        protected <T> T autoBuild(Class<T> type) {
            return type.cast(beanFactory.createBean(type, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, true));
        }
    }

    public static class MyService {
        private Date date;

        public MyService(Date date) {
            this.date = date;
        }

        public Date getDate() {
            return date;
        }
    }

    @Test
    public void testAutoBuild() {
        ApplicationContext appContext = new AnnotationConfigApplicationContext(MyConfiguration.class);
        MyService myService = appContext.getBean(MyService.class);
        Assert.assertEquals(12345, myService.getDate().getTime());
    }
}

person lance-java    schedule 27.11.2012    source источник


Ответы (1)


Конфигурация контейнера на основе Java никоим образом не зависит от сканирования компонентов. Это просто другой подход к конфигурации компонентов на основе XML. С конфигурацией XML вам просто нужно объявить свой bean-компонент с классом MyServiceImpl, если он уже аннотирован @inject. Spring распознает аннотации и позаботится о них. Если вы действительно хотите создать экземпляр MyServiceImpl из java-класса @Configuration, не вызывая конструктор самостоятельно, вам придется использовать фабрику компонентов (не проверял ее, просто попробуйте):

@Configuration
public class MyConfiguration {

    @Autowired AutowireCapableBeanFactory beanFactory;

    @Bean public MyService myService() { 
        return beanFactory.createBean(MyServiceImpl.class, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, true);
    }
}
person Stefan Podkowinski    schedule 27.11.2012
comment
Я понимаю, что конфигурация аннотаций не требует сканирования компонентов, но мне нужна функция автоматической сборки, которую использует сканирование компонентов. Ваш ответ привел меня к фрагменту кода, отвечающему за автосборку. Спасибо! - person lance-java; 28.11.2012