【问题标题】:Spring Accessing configuration - AlreadyBuiltException when setting variable using @ValueSpring访问配置-使用@Value设置变量时出现AlreadyBuiltException
【发布时间】:2016-08-13 19:40:49
【问题描述】:

我正在使用 Spring Security 实现 ldap 身份验证。当我在以下配置类中硬编码所有 ldap 服务器信息时,它可以工作。

//WebSecurityConfig.java
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .anyRequest()
                .authenticated()
                .and()
            .formLogin();
    }

    @Configuration
    protected static class AuthenticationConfiguration extends
            GlobalAuthenticationConfigurerAdapter {

        @Override
        public void init(AuthenticationManagerBuilder auth) throws Exception { 

            DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource("ldap://ldap.mdanderson.edu:389/dc=mdanderson,dc=edu");
            contextSource.setUserDn("cn=ris_flow,ou=service accounts,ou=institution,ou=service accounts,dc=mdanderson,dc=edu");
            contextSource.setPassword("xxxyyyzzz");
            contextSource.setReferral("follow"); 
            contextSource.afterPropertiesSet();  
            LdapAuthenticationProviderConfigurer<AuthenticationManagerBuilder> ldapAuthenticationProviderConfigurer = auth.ldapAuthentication();

            ldapAuthenticationProviderConfigurer
                .userDnPatterns("cn={0},ou=institution,ou=people")
                .userSearchBase("")
                .contextSource(contextSource);
        }
    }
}

我决定将这些服务器信息放在 application.properties 中,并在我的配置类中使用 @Value 设置变量,所以我在 AuthenticationConfiguration 之前添加了以下内容。

@Value("${ldap.contextSource.url")
private static String url;

@Value("${ldap.contextSource.managerDn")
private static String userDn;

@Value("${ldap.contextSource.managerPass")
private static String userPass;

并将 contextSource 的行替换为:

    DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource(url);
    contextSource.setUserDn(userDn);
    contextSource.setPassword(userPass);

但是当我再次运行它时,应用程序无法启动并出现以下错误:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'springSecurityFilterChain' defined in class path resource.......
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate....
Caused by: java.lang.IllegalArgumentException: An LDAP connection URL must be supplied.


org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'springSecurityFilterChain' defined in class path resource....
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate....
Caused by: org.springframework.security.config.annotation.AlreadyBuiltException: This object has already been built

我做错了什么?

【问题讨论】:

    标签: spring spring-security properties spring-boot spring-annotations


    【解决方案1】:

    检查这段代码

        @Value("${ldap.contextSource.url") 
    private static String url; 
        @Value("${ldap.contextSource.managerDn") 
    private static String userDn; 
        @Value("${ldap.contextSource.managerPass") 
    private static String userPass;
    

    您需要以这种方式正确关闭括号

    @Value("${ldap.contextSource.url}") private static String url; 
    @Value("${ldap.contextSource.managerDn}") private static String userDn; 
    @Value("${ldap.contextSource.managerPass}") private static String userPass;
    

    来自 Spring In Action 第四版:

    当依靠组件扫描和自动装配来创建和初始化你的 应用程序组件,没有可以指定占位符的配置文件或类。相反,您可以像使用@Autowired 注释一样使用@Value 注释。 为了使用占位符值,您必须配置 PropertyPlaceholderConfigurer bean 或 PropertySourcesPlaceholderConfigurer bean。从 Spring 3.1 开始,PropertySourcesPlaceholderConfigurer 是首选,因为它针对 Spring 环境及其属性源集解析占位符。 以下@Bean 方法配置 PropertySourcesPlaceholderConfigurer 在 Java 配置中:

    @Bean
    public
    static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }
    

    编辑:使用 SPRING 4.2.5 RELEASE 访问属性的完整示例

    配置类:

    @Configuration
    @ComponentScan
    @PropertySource("classpath:/your/package/example.properties")
    // In my case, this package is stored in src/main/resources folder, which is in the classpath of the application
    public class SpringPropertiesConfig {
    
        @Bean
        public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
            return new PropertySourcesPlaceholderConfigurer();
        }
    }
    

    组件(Bean)访问属性:

    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;
    
    @Component
    public class ComponentAccessingProperties {
    
        @Value("${first.property}")
        private String propertyOne;
    
        @Value("${second.property}")
        private String propertyTwo;
    
    
        public String getPropertyOne() {
            return propertyOne;
        }
    
        public String getPropertyTwo() {
            return propertyTwo;
        }
    
    }
    

    示例属性文件 (/your/package/example.properties):

    first.property=ONE
    second.property=SECOND
    

    测试类:

    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    import your.package.ComponentAccessingProperties;
    import your.package.SpringPropertiesConfig;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = SpringPropertiesConfig.class)
    public class TestAccessingProperties {
    
        @Autowired
        private ComponentAccessingProperties componentAccesingProperties;
    
        @Test
        public void shouldNotBeNull() {
            assertNotNull(componentAccesingProperties);
        }
    
        @Test
        public void checkProperties() {
            assertEquals("ONE", componentAccesingProperties.getPropertyOne());
            assertEquals("SECOND", componentAccesingProperties.getPropertyTwo());
        }
    }
    

    【讨论】:

    • 不幸的是还是一样
    • 好的,检查您的代码,在您的配置类中,您应该使用@PropertySource 注释该类以指示属性所在的位置并使用PropertiesPlaceholderConfigurer 类的bean。检查此链接,您可以在其中找到示例 websystique.com/spring/…。我没试过,但似乎没问题
    • 我收到错误FileNotFoundException: class path resource [application.properties] cannot be opened because it does not exist。我在/src/main/resources/config 下有我的application.properties。我认为这是在带有 Spring Boot 自动配置的类路径中。我在那个文件中有数据库连接信息,显然是正确拾取的。
    • 我知道“/src/main/resources”应该是类路径的主要资源文件夹,所以您的 application.properties 将位于 config/application.properties 中。尝试设置此路径“@PropertySource(value = { "classpath:config/application.properties" })”并告诉我好吗?
    • 你在值注解中使用了$或#?
    猜你喜欢
    • 1970-01-01
    • 2020-06-03
    • 2015-03-01
    • 2017-10-17
    • 1970-01-01
    • 2023-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多