2012-08-12 9 views
5

Sto provando a creare un PropertySource di Spring 3.1 che legge i suoi valori dai nodi Zookeeper. Per il collegamento a Zookeeper sto usando Curator da Netflix.L'origine della proprietà Spring personalizzata non risolve i segnaposto in @Value

Per questo ho creato una fonte di proprietà personalizzata che legge il valore di una proprietà da Zookeeper e lo restituisce. Questo funziona bene quando sto risolvendo la proprietà come questa

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

Tuttavia, quando cerco di istanziare un fagiolo che ha un campo con un'annotazione @Value allora questo non riesce:

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

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

Questo problema ha molto probabilmente non ha nulla a che fare con Zookeeper ma con il modo in cui sto registrando i sorgenti delle proprietà e creando i bean.

Qualsiasi intuizione è molto apprezzata.

Update 1:

che sto creando il contesto applicazione da un file XML in questo modo:

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

La classe che si collega a Zookeeper è un @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); 
    } 
} 

Update 2

Questo sembra funzionare quando sto usando configurazione XML-meno, vale a dire @Configuration, @ComponentScan e @PropertySource in combinazione con un AnnotationConfigApplicationContext. Perché non funziona con ClassPathXmlApplicationContext?

@Configuration 
@ComponentScan("com.goleft") 
@PropertySource({"classpath:config.properties","classpath:version.properties"}) 
public class AppConfig { 
    @Bean 
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { 
     return new PropertySourcesPlaceholderConfigurer(); 
    } 
} 

risposta

4

Rispondendo alla tua Update 2: Questo non funziona con la configurazione originale (registrazione di un PropertySource utilizzando @PostConstruct) perché il PropertySource viene registrato molto tardi, da questo momento il bean obiettivo è già stato costruito e inizializzato.

In genere l'iniezione dei segnaposto avviene tramite un BeanFactoryPostProcessor che è molto presto nel ciclo di vita della molla (fagioli non sono stati creati in questa fase) e se un PropertySource è registrato in quella fase, quindi segnaposto dovrebbero essere risolti.

L'approccio migliore però è quella di utilizzare un ApplicationContextInitializer, ottenere una maniglia sul applicationContext e per registrare il propertySource lì:

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

Potete per favore includere il codice AppConfig anche nel vostro aggiornamento. –

+0

Ho semplificato il problema ma ora non riesco più a farlo funzionare. Carica sempre dal file di configurazione. Beh, in realtà funziona nel mio progetto non semplificato ma solo con la classe AppConfig e quando la proprietà non esiste nel file config.properties. Come posso utilizzare ApplicationContextInitializer con un'applicazione non web? – magiconair

+1

Sì, hai ragione, funziona un po 'diverso. Ho inviato una richiesta di estrazione al repository con un test che si comporta in modo coerente per l'annotazione e il contesto dell'applicazione basato su xml. –

Problemi correlati