I have Spring context with several beans, like:
<bean id="anyBean" class="com.my.app.AnyBean"
p:test_user="${any1}"
p:test_pass="${any2}">
</bean>
To resolve these placeholders (${any1} and ${any2}) I use:
<bean id="propertyPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" p:location="my.properties" />
It works fine, but I need to define location of the 'my.properties' from 'main' method of the main class. Like this:
ApplicationContext context = new ClassPathXmlApplicationContext(my_xml_config.xml);
PropertyPlaceholderConfigurer ppc = context.getBean("propertyPlaceholderConfigurer", PropertyPlaceholderConfigurer.class);
Resource resource = context.getResource("path/to/my.properties");
ppc.setLocation(resource);
But when I try to launch it:
Exception in thread "main"
org.springframework.beans.factory.BeanDefinitionStoreException:
Invalid bean definition with name 'AnyBean' defined in class path
resource [my_xml_config.xml]: Could not resolve placeholder 'any1' in
string value "${any1}"
Could you hint is there any way to resolve this problem?
By the time you try to get a bean
PropertyPlaceholderConfigurer ppc = context.getBean("propertyPlaceholderConfigurer", PropertyPlaceholderConfigurer.class);
Spring has already tried to refresh your context and failed since the property isn't present. You need to prevent Spring from doing this by specifying it in the constructor
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"my_xml_config.xml"}, false);
Since the ApplicationContext is not refreshed, the PropertyPlaceholderConfigurer bean doesn't exist.
For this to work, you need to use a PropertySourcesPlaceholderConfigurer instead of a PropertyPlaceholderConfigurer (thanks M.Deinum). You can declare it in the XML in the same way as you did for the PropertyPlaceholderConfigurer bean, or use
<context:property-placeholder />
You need to take advantage of the fact that PropertySourcesPlaceholderConfigurer has its own locations, but also uses the PropertySource instances registered in the ApplicationContext's Environment.
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"your_config.xml"}, false);
// all sorts of constructors, many options for finding the resource
ResourcePropertySource properties = new ResourcePropertySource("path/to/my.properties");
context.getEnvironment().getPropertySources().addLast(properties);
context.refresh();
Related
What is the xml equivalent of the
#Autowired
private ApplicationContext appContext;
?
P.S.: When I try to google it I got a million results about how ApplicationContext works but not how to get it in the xml definition. The project is all writen using xml definition so I need to find a way how to do it without anotations.
First, configure your spring beans in file applicationContext.xml For example:-
<bean id="beanId"
class="com.java.spring.MyClassName">
</bean>
load the spring configuration file and retrieve bean from spring container
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
MyClass myBean = context.getBean("beanId",MyClass.class);
I try to get bean, by using ClassPathXmlApplicationContext. But I receive: NoSuchBeanDefinitionException: No bean named 'newsController' is defined
ApplicationContext applicationContext = new
ClassPathXmlApplicationContext("classpath*:conf/Spring_Config.xml");
NewsController newsController = (NewsController)
applicationContext.getBean("newsController");
In xml:
<bean id="newsController" class="NewsController"/>
Add full path to the bean class tag
class=com.foo.NewsController
I need to load bean definitions from XML. The file is in a remote location (http) which is configured by properties. The properties should also be loaded from a remote location (a spring cloud config server)
constraints:
Spring 4.3.14 (not boot)
should be in runtime and after my properties already loaded
beans defined in xml are referencing properties in context
server URI (to fetch the xml from) should be in properties and not environment variable or profile depandant
The current setup I have works well when MY_XML_URI is passed as environment variable:
${SPRING_CONFIG_URI}/master/application-${spring.profiles.active}.properties
<import resource="${MY_XML_URI}/myBeans.xml"/>
And in the remote location, myBeans.xml with lots of beans e.g.
<bean name="mySpecialBean" class="com.example.MyGenericBean">
<constructor-arg value="mySpecialBean"/>
<constructor-arg value="${special.bean.config.expression}"/>
</bean>
However trouble starts when I want to get MY_XML_URI from the properties context, it doesn't resolve
…
I have tried several approaches e.g:
java configuration class with #ImportResource({"${xml.server.uri}"})
but the properties are not loaded yet so it not converting to real value of xml.server.uri .
#Configuration
#ImportResource({"${xml.server.uri:http://localhost:8888}/myBeans.xml"})
public class MyConfiguration {}
expose dummy bean which fetch xml as resource and load the beans to parent applicationcontext - i must have it available to other beans dependant on those beans defined in xml. This solution was not injecting the properties context to my beans so failed to init them.
#Configuration
public class RiskConfig {
#Value("${xml.server.uri}")
private String xmlUri;
#Autowired
#Bean
public Object myBean(ApplicationContext applicationContext) {
Resource resource = applicationContext.getResource(xmlUri + "myBeans.xml");
// not working since its not loading the beans to the main context
// GenericApplicationContext genericApplicationContext = new GenericApplicationContext(applicationContext);
// XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(genericApplicationContext);
// reader.loadBeanDefinitions(resource);
AutowireCapableBeanFactory factory = applicationContext.getAutowireCapableBeanFactory();
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) factory;
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(registry);
reader.loadBeanDefinitions(resource);
return new Object();
}
}
Finally - is there a way to load the beans from xml programmatically to parent application context (which is already exist) though they are injected with properties.
As a Spring beginner I get used to use BeanFactory :
Resource res1 = new ClassPathResource("bus.xml");
BeanFactory factory1 = new XmlBeanFactory(res1);
Resource res2 = new ClassPathResource("travel.xml");
BeanFactory factory2 = new XmlBeanFactory(res2,factory1);
Those configuration comes since I'm using 2 separate XML configs. which using <ref parent="bus"> in travel.xml.
bus.xml
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
"http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="bus" class="java4s.Bus">
<property name="maxSpeed" value="80" />
</bean>
</beans>
Travel.xml
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
"http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="travel" class="java4s.Travel">
<property name="v">
<ref parent="bus" />
</property>
</bean>
</beans>
Thinking about using ApplicationContext I have a question how to make those configs to be equally to ApplicationContext, since in the above example factory1 instance need to be passed to XmlBeanFactory (...,...) as second argument of the constructor, I've tried to google it many times since this morning but can't find the exact example. I need to transform them to something like :
ApplicationContext con1 = new ClassPathXmlApplicationContext("bus.xml");
ApplicationContext con2 = new ClassPathXmlApplicationContext("travel.xml",con1);
Thanks.
Edit : I try #JorgeCampos's suggestion :
ApplicationContext con1 = new ClassPathXmlApplicationContext("bus.xml","travel.xml");
Object o = con1.getBean("travel");
Journey j = (Journey)o;
But throwing me an error :
Exception in thread "main"
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'travel' defined in class path resource
[travel.xml]: Cannot resolve reference to bean 'bus' while setting
bean property 'v'; nested exception is
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'travel' defined in class path resource
[travel.xml]: Can't resolve reference to bean 'bus' in parent factory:
no parent factory available
EDIT : I FOUND THE ANSWER:
it's :
new ClassPathXmlApplicationContext(new String[]{"travel.xml"}, new ClassPathXmlApplicationContext("bus.xml"));
which is written in docs as (is it ?)
public ClassPathXmlApplicationContext(String[] configLocations, ApplicationContext parent),
Thank you very much everyone! (specially #M. Deinum)
You should be able to compose multiple xml configuration files using the import element.
I have a .properties file having 10 key-values pairs say age =10, name=Jon etc. I have configured a bean in spring which has a map as a member variable.
When the bean is loaded by Spring once I call the getBean method, before that the Map should be loaded with the properties from files. How to do that ?
I know this should be done in one of the lifecycle methods like afterPropertiesSet using InitializingBean or init-method configuration. Is there any other better way to do this ?
You can enable annotations in your beans:
<context:annotation-config />
Then you can define method with #PostConstruct annotation. Spring will execute it during bean initialization process:
class MyBean {
private Map<String, String> properties;
#PostConstruct
public void initialize() {
// read properties and initialize map
}
}
Another option is to inject Properties directly into your bean and provide map-like API to access them:
<util:properties id="myProperties" location="classpath:my-props.properties">
<bean id="myBean" class="com.example.MyBean">
<property name="properties" ref="myProperties" />
</bean>
you can use context property-placeholder within XML spring configuration file using ${...} or from java class configuration file using #value.