Конфигурация Java Spring 3.1 - вызов @Autowired, @Configuration и @Profile - PullRequest
3 голосов
/ 01 сентября 2011

Я играю с Spring 3.1 и Servlet 3.0 и был действительно заинтригован новой опцией конфигурации Java, а также использованием профилей Spring и столкнулся с проблемой.Несмотря на то, что из всех примеров, которые я видел в Интернете, создается впечатление, что класс, аннотированный @Configuration, может содержать в себе другие объекты @Autowired, и я вижу, что автоматическое подключение не происходит до тех пор, пока некоторые из bean-компонентов вкласс @Configuration создан.

Вот мой инициализатор:

public class SpringMvcInitializer implements WebApplicationInitializer {

private static org.apache.log4j.Logger log= Logger.getLogger(SpringMvcInitializer.class);

@Override
public void onStartup(ServletContext servletContext) throws ServletException {
    // Create the 'root' Spring application context
    AnnotationConfigWebApplicationContext rootContext  = new AnnotationConfigWebApplicationContext();
    rootContext.scan("org.jc.config");
    servletContext.addListener(new ContextLoaderListener(rootContext));

    // Secures the application
    servletContext.addFilter("securityFilter", new DelegatingFilterProxy("springSecurityFilterChain"))
        .addMappingForUrlPatterns(null, false, "/*");       

    ServletRegistration.Dynamic appServlet =
            servletContext.addServlet("appServlet", new DispatcherServlet(new GenericWebApplicationContext()));
    appServlet.setLoadOnStartup(1); 

    appServlet.addMapping("/");

    log.info("Mvc Initializer starting");
}

My Web Config

@Configuration
@EnableWebMvc
@ComponentScan(basePackages="org.jc" )
public class WebConfig extends WebMvcConfigurerAdapter {

@Bean
public InternalResourceViewResolver configureInternalResourceViewResolver() {
    InternalResourceViewResolver resolver = new InternalResourceViewResolver();
    resolver.setPrefix("/WEB-INF/");
    resolver.setSuffix(".jsp");
    return resolver;
}

@Override
public void configureResourceHandling(ResourceConfigurer configurer) {
    configurer.addPathMapping("/resources/**");
    configurer.addResourceLocation("/resources/");
}

Мой класс конфигурации для JPA

@Configuration
public class JpaConfig {
private static Logger logger = Logger.getLogger(JpaConfig.class);

private AppEnvironmentI appEnvironment;

@Autowired
public void setAppEnvironment(AppEnvironmentI appEnvironment) {
    this.appEnvironment = appEnvironment;
    checkAppEnv("setAppEnvironment");
}

@Bean
public AppUser globalUser(){
    checkAppEnv("globalUser entry");
    AppUser appUser = new AppUser();
    checkAppEnv("globalUser exit");
    return appUser;
}

@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(){
    checkAppEnv("entityManagerFactory entry");
    LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean ();
    emf.setDataSource(dataSource());
    emf.setJpaVendorAdapter(this.jpaAdapter());
    emf.setPersistenceUnitName("JcEntities2");
    checkAppEnv("entityManagerFactory exit");
    return emf;
}

@Bean
public DataSource dataSource(){
    checkAppEnv("dataSource entry");
    DriverManagerDataSource ds = new DriverManagerDataSource();
    ds.setDriverClassName("org.apache.derby.jdbc.EmbeddedDriver");
    ds.setUrl("jdbc:derby://localhost:1527/JcTestDb");
    ds.setUsername("jc");
    ds.setPassword("pwd");
    checkAppEnv("dataSource exit");
    return ds;
}

@Bean
public JpaVendorAdapter jpaAdapter() {
    checkAppEnv("jpaAdapter entry");
    HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
    hibernateJpaVendorAdapter.setShowSql(true);
    hibernateJpaVendorAdapter.setDatabase(Database.DERBY);
    checkAppEnv("jpaAdapter exit");
    return hibernateJpaVendorAdapter;
}

@Bean
public PlatformTransactionManager transactionManager() {
    checkAppEnv("transactionManager entry and exit");
    return new JpaTransactionManager( entityManagerFactory().getObject() );
}

private void checkAppEnv(String _method){
    if(this.appEnvironment == null){
        logger.info(_method + " - App Environment is null!!!!");
    }else{
        logger.info(_method + " - App Environment JpaConfig = " + appEnvironment.externalPropertiesFile().getPropertyValue("environment"));
    }
}

Мой профиль класса

@Configuration
@Profile("local")
public class AppEnvironmentLocal implements AppEnvironmentI{
private static Logger logger = Logger.getLogger(AppEnvironmentLocal.class);

@Bean
public AppEnvironment externalPropertiesFile(){
    logger.info("Fetching properties file for LOCAL environment");
    Properties props = FileUtilsJc.getPropertiesFromFlatFile("C:\\AppConf\\JcConf\\JcConfLocal.properties");
    AppEnvironment exf = new AppEnvironment(props);
    return exf;
}
}

Вывод логгера: похоже, что Spring 3.1 сначала пытается создать объектный компонент Entity Manager Factory, прежде чем AppEnvironment будет введен в класс.Таким образом, он создает все компоненты, кроме Global User (фиктивный компонент, который я вставил для тестирования) и Transaction Manager, внедряет AppEnvironment, а затем создает глобальные компоненты и диспетчер транзакций.

Любые идеи с благодарностью!

01-Sep-2011 10:20:55  INFO Mvc Initializer starting
01-Sep-2011 10:20:55  INFO entityManagerFactory entry - App Environment is null!!!!
01-Sep-2011 10:20:55  INFO dataSource entry - App Environment is null!!!!
01-Sep-2011 10:20:55  INFO dataSource exit - App Environment is null!!!!
01-Sep-2011 10:20:55  INFO jpaAdapter entry - App Environment is null!!!!
01-Sep-2011 10:20:55  INFO jpaAdapter exit - App Environment is null!!!!
01-Sep-2011 10:20:55  INFO entityManagerFactory exit - App Environment is null!!!!
01-Sep-2011 10:20:55  INFO Fetching properties file for LOCAL environment
01-Sep-2011 10:20:55  INFO setAppEnvironment - App Environment JpaConfig = LOCAL

Вот URL-адрес примера кода, который я использовал для подключения:

http://blog.springsource.com/2011/02/14/spring-3-1-m1-introducing-profile/

Я нашел документацию о том, что до Spring 3.1 необходимо было добавить @AnnotationDrivenConfigаннотации к вашему инъекционному классу для того, чтобы @Autowired работал, но это не рекомендуется в Spring 3.1. Я нашел кучу постов, которые искали эту аннотацию, но ничего не было адресовано, когда будет введен объект конфигурации!

1 Ответ

2 голосов
/ 01 сентября 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...