java - @Value at runtime -
how access @value machinery dynamically @ run-time?
i thought environment might looking for, it
@component public class springconfiguration implements configurationi { @autowired private provider<environment> env; @override public string get(string key) { try { return env.get().getrequiredproperty(key); } catch (illegalstateexception e) { return null; } } }
unfortunately, not access values exposed our propertyplaceholderconfigurer
bean.
edit: explain use case: part of making library lot of spring specific pieces (that pile of older spring applications depend on) usable newer guice applications switching spring specific annotations jsr 330 (javax.inject) ones. hoping avoid rewriting propertyplaceholderconfigurer
stuff across our spring applications, providing nice entrypoint this. if there better way (maybe @named?) ears.
edit2: (cleaned up) example of kind of propertyplaceholderconfigurer exists in apps calling library.
@bean public propertyplaceholderconfigurer placeholderconfigurer() { return new propertyplaceholderconfigurer() { @override protected string resolveplaceholder(string placeholder, properties props) { // code parse , cleanup key here string result = getpropertyfromlocalappspecificconfig(key); if (result == null) { result = super.resolveplaceholder(placeholder, props); } // more random app specific logic missing defaults return result; } }; }
propertyplaceholder
, friends not put properties in environment
(mainly because of backward compatibility reasons). instead use environment , own internal properties
object gathered property files classpath resolve @value
properties. properties loaded propertyplaceholder can not fetched dynamically (ie no getproperty(string..)
). people create custom propertyplaceholder
store properties publicly (through getter or whatever) think defeats spring's new unified environment configuration handling.
what want @propertysource
still pretty crappy since not dynamic (since annotation can't change files loaded from) load properties environment
. have been meaning file issues spring source confusion of this.
anyway can @ solution here: manually add @propertysource: configuring environment before context refreshed
basically need hold of configurableenvironment
, load properties creating propertysources
. api powerful not intuitive. can use applicationcontextinitializers
environment
has own annoying issues (see link) or can below.
public class configresourcesenvironment implements resourceloaderaware, environmentaware, beandefinitionregistrypostprocessor, environmentpropertiesmapsupplier { private environment environment; private map<string, string> environmentpropertiesmap; @override public void postprocessbeandefinitionregistry(beandefinitionregistry registry) throws beansexception { if (environment instanceof configurableenvironment) { configurableenvironment env = ((configurableenvironment) this.environment); list<propertysource> propertysources; try { propertysources = loadpropertysources(); //your custom method propertysources } catch (ioexception e) { throw new runtimeexception(e); } //spring prefers primacy ordering reverse order of sources... may not need this. reverse(propertysources); (propertysource rp : propertysources) { env.getpropertysources().addlast(rp); } environmentpropertiesmap = immutablemap.copyof(environmentpropertiestomap(env)); } else { environmentpropertiesmap = immutablemap.of(); } } public static map<string,string> environmentpropertiestomap(configurableenvironment e) { map<string, string> properties = newlinkedhashmap(); (string n : propertynames(e.getpropertysources())) { string v = e.getproperty(n); if (v != null) properties.put(n, v); } return properties; } public static iterable<string> propertynames(propertysources propertysources) { linkedhashset<string> propertynames = new linkedhashset<string>(); (propertysource<?> p : propertysources) { if (p instanceof enumerablepropertysource) { enumerablepropertysource<?> e = (enumerablepropertysource<?>) p; propertynames.addall(aslist(e.getpropertynames())); } } return propertynames; } @override public void postprocessbeanfactory(configurablelistablebeanfactory beanfactory) throws beansexception { //noop } @override public void setenvironment(environment environment) { this.environment = environment; } public map<string, string> getenvironmentpropertiesmap() { return environmentpropertiesmap; } }
once have configurableenvironment
loaded can use environmentaware
interface things need environment or create own interface.
here custom interface can use things need dynamic properties (the above class implements it):
public interface environmentpropertiesmapsupplier { public map<string, string> getenvironmentpropertiesmap(); }
Comments
Post a Comment