微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

自定义spring属性源不解析@Value中的占位符

我正在尝试构建一个Spring 3.1 PropertySource,它从Zookeeper节点读取它的值.为了连接到Zookeeper,我使用的是Netflix的Curator.

为此,我构建了一个自定义属性源,它从Zookeeper读取属性的值并返回它.当我解析这样的属性时,这很好用

ZookeeperPropertySource zkPropertySource = new ZookeeperPropertySource(zkClient);
ctx.getEnvironment().getPropertySources().addLast(zkPropertySource);
ctx.getEnvironment().getProperty("foo"); // returns 'from zookeeper'

但是,当我尝试实例化一个带有@Value注释的字段的bean时,这会失败:

@Component
public class MyBean {
    @Value("${foo}") public String foo;
}

MyBean b = ctx.getBean(MyBean.class); // fails with BeanCreationException

这个问题很可能与Zookeeper没有任何关系,但是我正在注册属性源并创建bean.

任何见解都受到高度赞赏.

更新1:

我正在从这样的XML文件创建应用程序上下文:

public class Main {
    public static void main(String[] args) throws Exception {
        ConfigurableApplicationContext ctx = new ClasspathXmlApplicationContext("applicationContext.xml");
        ctx.registerShutdownHook();
    }
}

连接到Zookeeper的类是@Component.

@Component
public class Server {
    CuratorFramework zkClient;

    public void connectToZookeeper() {
        zkClient = ... (curator magic) ...
    }

    public void registerPropertySource() {
        ZookeeperPropertySource zkPropertySource = new ZookeeperPropertySource(zkClient);
        ctx.getEnvironment().getPropertySources().addLast(zkPropertySource);
        ctx.getEnvironment().getProperty("foo"); // returns 'from zookeeper'
    }

    @postconstruct
    public void start() {
        connectToZookeeper();
        registerPropertySource();
        MyBean b = ctx.getBean(MyBean.class);
    }
}

更新2

当我使用无XML配置时,这似乎有效,即@Configuration,@ ComponentScan和@PropertySource与AnnotationConfigApplicationContext结合使用.为什么它不能用于ClasspathXmlApplicationContext?

@Configuration
@ComponentScan("com.goleft")
@PropertySource({"classpath:config.properties","classpath:version.properties"})
public class AppConfig {
    @Bean
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }
}
最佳答案
回答您的更新2:这不适用于您的原始配置(使用@postconstruct注册PropertySource),因为PropertySource注册很晚,此时您的目标bean已经构建并初始化.

通常,占位符的注入是通过BeanFactoryPostProcessor进行的,这是在Spring生命周期的早期(在此阶段尚未创建bean),如果在该阶段注册了PropertySource,则应解析占位符.

最好的方法是使用ApplicationContextInitializer,获取applicationContext的句柄并在那里注册propertySource:

public class CustomInitializer implements ApplicationContextinitializerfigurableWebApplicationContext> {
    public void initialize(ConfigurableWebApplicationContext ctx) {
        ZookeeperPropertySource zkPropertySource = new ZookeeperPropertySource(zkClient);
        ctx.getEnvironment().getPropertySources().addFirst(zkPropertySource);
    }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐