How to reuse Spring XML fragments - java

I am working on Spring based application. The XML is simple but contains several almost identical fragments. For example I have 5 different DAO objects, 2 queues etc. Configuration of each DAO looks like:
<bean id="deviceDaoTarget" class="com.mycompany.dao.hibernate.DeviceDAOHibernateImpl"
autowire="byName" />
<bean id="deviceDAO" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>com.mycompany.dao.DeviceDAO</value>
</property>
<property name="interceptorNames">
<list>
<value>hibernateInterceptor</value>
<value>deviceDaoTarget</value>
</list>
</property>
</bean>
I'd be happy to use some kind of import with parameters. For example I'd like to create parametrized configuration of DAO like this:
<bean id="${dao.target}" class="${dao.class}"
autowire="byName" />
<bean id="deviceDAO" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>${dao.interface}</value>
</property>
<property name="interceptorNames">
<list>
<value>hibernateInterceptor</value>
<value>${dao.target}</value>
</list>
</property>
</bean>
and then call it several times with different parameters, e.g.:
<import resource="spring-dao.xml">
<param name="dao.interface">com.mycompany.dao.hibernate.DeviceDAO</param>
<param name="dao.class">com.mycompany.dao.hibernate.DeviceDAOHibernateImpl</param>
<param name="dao.target">deviceDaoTarget</param>
</import>
Is something like this possible?

You can define a <bean id="parentBean" abstract="true" ...>...</bean> with the common configuration and then have <bean id="childBean" parent="parentBean" ...>...</bean> with just specific configuration for that bean.

Related

Spring. How to add same property to multiple beans?

Consider I have something like this in beans.xml:
<bean id="emails" class="org.some.package.SomeClass">
<property name="emailList">
<list>
<value>pechorin#hero.org</value>
<value>raskolnikov#slums.org</value>
<value>stavrogin#gov.org</value>
<value>porfiry#gov.org</value>
</list>
</property>
</bean>
But I need to add emailList property into multiple beans. How can I do that without writing property to each bean? Can externalize property and inject it into each bean?
I expect something like:
<property name="commonProp">
<list>
<value>pechorin#hero.org</value>
<value>raskolnikov#slums.org</value>
<value>stavrogin#gov.org</value>
<value>porfiry#gov.org</value>
</list>
</property>
<bean id="emailsOne" class="org.some.package.ClassOne">
<property name="emailList" ref="commonProp" />
</bean>
<bean id="emailsTwo" class="org.some.package.ClassTwo">
<property name="emailList" ref="commonProp" />
</bean>
You can do it using: util:list
<util:list id="myList" value-type="java.lang.String">
<value>foo</value>
<value>bar</value>
</util:list>
Then use this myList reference in other beans.

How can I use environment variable in hibernate config file?

I am currently using database parameters in hibernate(Version 4.0.1) file through properties file.
I want to use some database parameters from environment variable. How can I fetch values from java files and set in to xml files before that loads in context.
<bean id="propertyConfigurer"
class="org.jasypt.spring31.properties.EncryptablePropertyPlaceholderConfigurer">
<constructor-arg ref="configurationEncryptor" />
<property name="locations">
<list>
<value>classpath:/test/demo/prop/DataParam.properties</value>
</list>
</property>
</bean>
<bean id="data" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass">
<value>${driverClass}</value>
</property>
<property name="jdbcUrl">
<value>${dbconnecturl}</value>
</property>
.
.
.
</beans>
I got some idea to make an object of Configuration class but I don't know where to write that code and how it would be implemented.
You need to use spring expression language to configure the properties from OS environemnt variables as shown below:
<bean id="propertyConfigurer"
class="org.jasypt.spring31.properties.EncryptablePropertyPlaceholderConfigurer">
<constructor-arg ref="configurationEncryptor" />
<property name="locations">
<list>
<value>classpath:/test/demo/prop/DataParam.properties</value>
</list>
</property>
</bean>
<bean id="data" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass">
<value>#{ systemProperties['driverClass']}</value>
</property>
<property name="jdbcUrl">
<value>#{ systemProperties['dbconnecturl']}</value>
</property>
.
.
.
</beans>
You can use as <property name="username" value="#{systemProperties['dbUsername']}"/> for instance.
The variable systemProperties is predefined, you can see Xml Based Configuration for more details.

Order of bean initialization in Spring

I have the following beans in my Spring config file:
<bean id="myList" class="java.util.ArrayList">
<constructor-arg>
<list>
<ref bean="elem1"/>
<ref bean="elem2"/>
<ref bean="elem3"/>
<ref bean="elem4"/>
</list>
</constructor-arg>
</bean>
<bean id="elem4" class="myClass">
<property name="title" value="random4"/>
</bean>
<bean id="elem1" class="myClass">
<property name="title" value="random1"/>
</bean>
<bean id="elem3" class="myClass">
<property name="title" value="random3"/>
</bean>
<bean id="elem2" class="myClass">
<property name="title" value="random2"/>
</bean>
I have noticed that in my application the elements in myList are in the following order: elem4, elem1, elem3, elem2. I was expecting that the elements in my list will be in the order I set when I declared the ref beans ( elem1, elem2, elem3, elem4).
Is there an order in which Spring initializes beans?
Is there a way I can specify an order for the elements in my list?
The spring does respect the order you gave in the list. The elements in the list would exactly be the [elem1,elem2,elem3,elem4] as you specified. Otherwise, you are doing something wrong, can you show the code which prints you the different order?
The order of bean initialization however may be different and depends on bean dependencies, so, for example if you have two beans
<bean id="holder" class="my.HolderBean" lazy-init="false">
<property name="inner" ref="inner"/>
</bean>
<bean id="inner" class="my.InnerBean" lazy-init="false"/>
Then regardless of the xml definition order, the InnerBean will be initialized first, then during HolderBean initialization it will be injected into HolderBean.

Can't load multiple property files in spring's application context

I have three property files placed in a resource folder in classpath. The problem i am facing is while i am able to load invidual files separately i am unable to load them when they are declared together.
Please see the XML below:
<bean name="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames" value="resources\label"/>
</bean>
This is working but the XML given below isn't:
<bean name="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basenames" value="resources\label,resources\button,resources\messages"/>
<property name="cacheSeconds" value="1"/>
</bean>
I wish to declared them together as I wish to use a single bean to access all three files. Help required!
Found the answer . It should be like this `
<property name="basenames">
<list>
<value>classpath:resources\label</value>
<value>classpath:resources\button</value>
<value>classpath:resources\messages</value>
</list>
</property>
</bean>
Do it like this
<property name="basenames">
<list>
<value>resources\label</value>
<value>resources\button</value>
<value>resources\messages</value>
</list>
</property>

How to make embedded Jetty use the AppContext it's defined in as parent context for servlets

I have a standalone java app that now runs an embedded Jetty server to expose a RESTful API for HTTP. It does make heavy use of Spring beans for everything from Hibernate to Jetty. I have Jetty configured with a DispatcherServlet ( the thought being that adding a non-REST API in the future will be as simple as making the new Controller and mapping it correctly for the dispatcher).
My app has a class with a main method that creates a ClassPathXmlApplicationContext from my appContext.xml to start everything up.
ApplicationContext ac= new ClassPathXmlApplicationContext(new String[] { "appContext.xml" });
I don't know how to make beans defined in the context config file for the DispatcherServlet have access to beans defined in the appContext.xml where jetty is defined. My Jetty definition looks like this:
<bean id="JettyServer" class="org.eclipse.jetty.server.Server" init-method="start" destroy-method="stop">
<constructor-arg>
<bean id="threadPool" class="org.eclipse.jetty.util.thread.QueuedThreadPool">
<property name="minThreads" value="2"/>
<property name="maxThreads" value="10"/>
</bean>
</constructor-arg>
<property name="connectors">
<list>
<bean id="Connector" class="org.eclipse.jetty.server.ServerConnector">
<constructor-arg ref="JettyServer"/>
<property name="port" value="8090"/>
</bean>
</list>
</property>
<property name="handler">
<bean id="handlers" class="org.eclipse.jetty.server.handler.HandlerCollection">
<property name="handlers">
<list>
<bean class="org.eclipse.jetty.servlet.ServletContextHandler">
<property name="contextPath" value="/"/>
<property name="servletHandler">
<bean class="org.eclipse.jetty.servlet.ServletHandler">
<property name="servlets">
<list>
<bean class="org.eclipse.jetty.servlet.ServletHolder">
<property name="name" value="DefaultServlet"/>
<property name="servlet">
<bean class="org.springframework.web.servlet.DispatcherServlet"/>
</property>
<property name="initParameters">
<map>
<entry key="contextConfigLocation" value="classpath:./DefaultServlet.xml" />
</map>
</property>
</bean>
</list>
</property>
<property name="servletMappings">
<list>
<bean class="org.eclipse.jetty.servlet.ServletMapping">
<property name="pathSpecs">
<list><value>/</value></list>
</property>
<property name="servletName" value="DefaultServlet"/>
</bean>
</list>
</property>
</bean>
</property>
</bean>
<bean class="org.eclipse.jetty.server.handler.RequestLogHandler">
<property name="requestLog">
<bean class="org.eclipse.jetty.server.NCSARequestLog">
<constructor-arg value="/opt/impulse/logs/jetty-yyyy_mm_dd.log"/>
<property name="extended" value="false" />
</bean>
</property>
</bean>
</list>
</property>
</bean>
</property>
</bean>
Then in DefaultServlet.xml I try to defined a bean with a property references a bean defined in appContext.xml, which is what breaks.
<bean id="restApiController" class="com.mycompany.myapp.api.controllers.RESTfulController">
<property name="someBean" ref="someBean"/>
</bean>
You are bootstrapping Jetty with applicationContext.xml, which in turn sets up jetty with your servlet configuration. Inside it you are configuring your servlet with the contextConfigLocation parameter pointing to the servlet application context. It will still run as a webapp, even if you embed it. So you need to provide your servlet with the config to your other beans as well. I suggest that you extract the jetty setup into it's own file, and then the rest of your beans in a different file. You then supply the other context file in the contextConfigLocation.
Edit
If you really need to share the application context between jetty and your servlet, maybe you can use some of the information in this blog. It seems to be possible, but it looks like you have to wire up the parent/child relationship between the contexts manually.
For me, what worked is setting of ResourceConfig. With DispatcherServlet server was not even able to serve Rest call. So I used ServletContainer. Now Rest call worked but not able to access beans loaded in ApplicationContext. There ResourceConfig registration helped. Below was my configuration that I came up after long R & D. I had Jetty version 9.2.11.v20150529 and Spring 4.1.2.RELEASE
<bean class="org.eclipse.jetty.servlet.ServletHolder">
<property name="name" value="DefaultServlet"/>
<property name="servlet">
<bean id="servletContainer" class="org.glassfish.jersey.servlet.ServletContainer">
<constructor-arg>
<ref bean="config" />
</constructor-arg>
</bean>
</property>
</bean>
<bean id="config" class="org.glassfish.jersey.server.ResourceConfig" />
Basically I set ResourceConfig under ServletContainer. Then in application, I fetched all beans loaded in my applicationContext and register with this Resource config like below
ResourceConfig restConfig = (ResourceConfig)webContext.getBean("config");
String[] beans = context.getBeanDefinitionNames();
for(String bean : beans)
restConfig.registerInstances(context.getBean(bean));
Well, webContext here is WebAppContext which is required instead of ServletContaxtHandler. So instead of below lines as mentioned in question
<bean class="org.eclipse.jetty.servlet.ServletContextHandler">
<property name="contextPath" value="/"/>
I have
<!-- To work with Spring , we need WebAppContext instead of ServletContext -->
<!-- <bean id="servletContextHandler" class="org.eclipse.jetty.servlet.ServletContextHandler"> -->
<constructor-arg name="webApp" value="./target/classes/" />
<constructor-arg name="contextPath" value="/" />

Categories