2

I am stuck with null values in an autowired property. I am hoping I could get some help.

We are using for the project spring-boot version 0.5.0.M6.

The four configuration files with beans are in one package and are sorted by "area":

  1. Data source configuration
  2. Global method security configuration (as we use Spring-ACL)
  3. MVC configuration
  4. Spring Security configuration

The main method that bootstraps everything is in the following file:

@EnableAspectJAutoProxy
@EnableSpringConfigured
@EnableAutoConfiguration(exclude = {
    DataSourceTransactionManagerAutoConfiguration.class,
    HibernateJpaAutoConfiguration.class,
    JpaRepositoriesAutoConfiguration.class,
    SecurityAutoConfiguration.class,
    ThymeleafAutoConfiguration.class,
    ErrorMvcAutoConfiguration.class,
    MessageSourceAutoConfiguration.class,
    WebSocketAutoConfiguration.class
})
@Configuration
@ComponentScan
public class IntegrationsImcApplication {

    public static void main(String[] args) throws Exception {
        ApplicationContext ctx = SpringApplication.run(
                IntegrationsImcApplication.c lass, args);
    }
}

The first file that holds the data source configuration beans is as follows (I have omitted some method body parts to make it more readable):

@EnableTransactionManagement(mode = AdviceMode.ASPECTJ)
@Configuration
public class RootDataSourceConfig 
        extends TomcatDataSourceConfiguration 
        implements TransactionManagementConfigurer {

    @Override
    public DataSource dataSource() {
        return jpaDataSource();
    }

    public PlatformTransactionManager annotationDrivenTransactionManager() {
        return jpaTransactionManager();
    }

    @Bean
    public HibernateExceptionTranslator hibernateExceptionTranslator() {
        return new HibernateExceptionTranslator();
    }

    @Bean(name="jpaDataSource")
    public DataSource jpaDataSource() {......}

    @Bean(name = {"transactionManager","txMgr"})
    public JpaTransactionManager jpaTransactionManager() {......}

    @Bean(name = "entityManagerFactory")
    public EntityManagerFactory jpaEmf() {......}
}

And here is the next configuration file, that depends on the data source from above. It has about 20 beans related to ACL configuration, but it fails on the firsts bean that uses data source:

@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
public class RootGlobalMethodSecurityConfig 
        extends GlobalMethodSecurityConfiguration 
        implements Ordered {

    @Autowired
    public DataSource dataSource;

    @Override
    public int getOrder() {
        return IntegrationsImcApplication.ROOT_METHOD_SECURITY_CO NFIG_ORDER;
    }

    @Bean
    public MutableAclService aclService() 
            throws CacheException, IOException {

        MutableJdbcAclService aclService = new MutableJdbcAclService(
                dataSource, aclLookupStrategy(), aclCache());
        aclService.setClassIdentityQuery("SELECT @@IDENTITY");
        aclService.setSidIdentityQuery("SELECT @@IDENTITY");
        return aclService;
    }

    ...................................
}

Basically invoking aclService() throws an error as dataSource is null. We have tried ordering the configuration files by implementing the Ordered interface. We also tried using @AutoConfigureAfter(RootDataSourceConfig.class) but this did not help either. Instead of doing @Autowired on the DataSource we also tried injecting the RootDataSourceConfig class itself, but it was still null. We tried using @DependsOn and @Ordered on those beans but again no success. It seems like nothing can be injected into this configuration.

The console output at the startup is listing the beans in the order we want them, with data source being the first. We are pretty much blocked by this.

Is there anything weird or unique we are doing here that is not working? If this is as designed, then how could we inject data source differently?

Repo: github

4

2 回答 2

4

依赖于 a 的 bean 的急切初始化DataSource绝对是问题所在。根本原因与 Spring Boot 或自动配置无关,而是通过一个由BeanPostProcessor. bean 只能由早就初始化的东西进行后处理。DataSource在这种情况下,注入还为时过早(实际上@Configuration需要的类DataSource被实例化得太早而无法正确包装在@Configuration处理机器中,因此无法自动装配)。我的建议(这只会使您与缺少的 相同点AuthenticationManager)是将 声明GlobalMethodSecurityConfiguration为嵌套类,而不是DataSource需要:

@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
protected static class ActualMethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {

    @Autowired
    @Qualifier("aclDaoAuthenticationProvider")
    private AuthenticationProvider aclDaoAuthenticationProvider;

    @Autowired
    @Qualifier("aclAnonymousAuthenticationProvider")
    private AnonymousAuthenticationProvider aclAnonymousAuthenticationProvider;

    @Autowired
    @Qualifier("aclExpressionHandler")
    private MethodSecurityExpressionHandler aclExpressionHandler;

    @Override
    protected void configure(AuthenticationManagerBuilder auth)
            throws Exception {
        auth.authenticationProvider(aclDaoAuthenticationProvider);
        auth.authenticationProvider(aclAnonymousAuthenticationProvider);
    }

    @Override
    public MethodSecurityExpressionHandler createExpressionHandler() {
        return aclExpressionHandler;
    }

}

即把它粘在里面RootMethodSecurityConfiguration并从那个类中删除@EnableGlobalMethodSecurity注释。

于 2014-01-02T22:09:25.203 回答
0

我可能已经解决了这个问题。

GlobalMethodSecurityConfiguration.class具有以下尝试自动装配权限评估器的设置器:

@Autowired(required = false)
public void setPermissionEvaluator(List<PermissionEvaluator> permissionEvaluators) {
    ....
}

在我的情况下,aclPermissionEvaluator()bean 需要aclService()bean,而后者又取决于另一个自动装配的属性:dataSource. 这似乎还没有自动装配。

为了解决这个问题,我实施BeanFactoryAware并从中dataSource获取beanFactory

public class RootMethodSecurityConfiguration extends GlobalMethodSecurityConfiguration implements BeanFactoryAware {

    private DataSource dataSource;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.dataSource = beanFactory.getBean("dataSource", DataSource.class);
    }
    ....
}

在此之后,出现了其他异常,SecurityAutoConfiguration.class抱怨缺少 AuthenticationManager,所以我只是将其排除在@EnableAutoConfiguration. 我不确定它是否理想,但我有自定义安全配置,所以这样一切正常。

于 2014-01-02T06:01:39.320 回答