Как программно создать контекст Spring? - PullRequest
6 голосов
/ 10 июня 2009

Кто-нибудь знает, есть ли способ, которым я могу программно создать контекст бина?

Я хочу иметь возможность сделать что-то вроде:

ConfigurableApplicationContext c = new ConfigurableApplicationContext();
BeanDefinition bd = new BeanDefinition();
bd.setId("id");
bd.setClassName("classname");
bd.setProperty("propertyName", propertyValue");
...etc...

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

c.addBean("beanId", beanObject);

Или, если я использую аннотации:

c.setAnnotationAware(true);
c.setAnnotationScanBasePackage("packagename");

или

c.addAnnotatedSpringClass("classnamethatisannotated");

Основанием для этого является то, что я хочу иметь возможность переопределять определения bean-компонентов для целей тестирования. В своем тесте я создаю этот новый контекст приложения, настроенный с помощью кода в тесте (не в xml), а затем создаю это тестовое приложение. у контекста есть родительский контекст приложения SUT.

Я не нашел ни одного кода в библиотеках Spring, который мог бы сделать это. Кто-нибудь построил что-то подобное? Можно ли построить что-то подобное? Я знаю, что первый подход выполним, но я не уверен на 100%, что второй подход будет работать без условий.

Ответы [ 5 ]

9 голосов
/ 10 июня 2009

Попробуйте либо:


Пример кода JavaConfig

@Configuration
public class AppConfig {
    @Bean
    public TransferService transferService() {
        return new TransferServiceImpl();
    }
}

Пример кода BeanBuilder

def bb = new grails.spring.BeanBuilder()

bb.beans { 
  dataSource(BasicDataSource) { 
    driverClassName = "org.hsqldb.jdbcDriver" 
    url = "jdbc:hsqldb:mem:grailsDB" 
    username = "sa" 
    password = "" 
  } 

  sessionFactory(ConfigurableLocalSessionFactoryBean) { 
    dataSource = dataSource
    hibernateProperties = [ "hibernate.hbm2ddl.auto":"create-drop", "hibernate.show_sql":true ] 
  }   
}

Пример кода AtUnit

Юнит тест

@RunWith(AtUnit.class)
@Container(Container.Option.SPRING)
@MockFramework(MockFramework.Option.EASYMOCK)
public class ExampleSpringEasyMockTest {

    @Bean @Unit UserManagerImpl manager;
    @Bean("fred") User fred;
    @Bean("userDao") @Mock UserDao dao;
    @Bean("log") @Stub Logger log;

    @Test
    public void testGetUser() {
        expect(dao.load(1)).andReturn(fred);
        replay(dao);
        assertSame(fred, manager.getUser(1));
        verify(dao);
    }


}

Файл контекста (приватный для теста)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">

  <bean id="userManager" class="atunit.example.subjects.UserManagerImpl">
      <constructor-arg ref="log"/>
      <property name="userDao" ref="userDao"/>
  </bean>

  <bean id="fred" class="atunit.example.subjects.User">
      <property name="id" value="500"/>
      <property name="username" value="fred"/>
  </bean>

</beans>
4 голосов
/ 10 июня 2009

В Spring вы можете переопределить определение bean-компонента так же легко, как заставить его снова появиться в файле. Мы часто используем это для той цели, которую вы описали; иметь другое определение компонента для модульных тестов, чем для производства.

Это шаблон, который мы используем для нашего test-context.xml

<import resource="classpath:production-context.xml">

<bean id="overriddenBean" class="com.MyClass">
   ....
</bean>

Это означает, что bean-компонент с id = overriddenBean будет связан с классами в ваших рабочих контекстах, если на него есть ссылка. Позволяет вам поменять бины, которые вам нужны для тестирования, вместо тех, которые вам нужны для производственного кода.

Надеюсь, это поможет

4 голосов
/ 10 июня 2009

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

3 голосов
/ 04 августа 2009

Просто добавьте постпроцессор бобов, который может манипулировать / добавлять любое определение бина

    public class ABeanFactoryPostProcessor implements
        BeanFactoryPostProcessor {

    public void postProcessBeanFactory(
            ConfigurableListableBeanFactory beanFactory) throws BeansException {

            if (beanFactory instanceof BeanDefinitionRegistry) {
            BeanDefinition beanDefinition=...

                ((BeanDefinitionRegistry)beanFactory).registerBeanDefinition(name, beanDefinition);
            }
    }

}
1 голос
/ 12 января 2014

Существует совершенно новый способ сделать это - Spring Boot

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;

@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application implements CommandLineRunner {

    private static final Logger LOG = LoggerFactory.getLogger(Application.class);

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        LOG.info("Hello world");
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...