I have a small Java application which connects to a MySQL database. For database connectivity ONLY, I'd like to use Spring to manage a JNDI based connection pool.
I have a working implementation for the above but this requires manually loading the JNDI connection bean, whereas I'd like to use #Autowired.
How can I convert my working code to one that uses #Autowired to get the JNDI connection ?
This is my beans.xml file (inside src/main/resources folder):
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns= ....>
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/Database"/>
</bean>
<bean id="databaseMapper2Impl"
class="com.dataaccess.DatabaseMapper2Impl">
<property name="dataSource" ref="dataSource" />
</bean>
</beans>
The is a section of my DatabaseMapper2Impl class:
public class DatabaseMapper2Impl {
private DataSource dataSource;
private JdbcTemplate jdbcTemplateObject;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
this.jdbcTemplateObject = new JdbcTemplate(dataSource);
}
public OrderDTO getOrder(String orderNumber, String envToUse) {
String getOrderSql = "SELECT * FROM REPORTING.ORDER where ORDER_NUMBER = ? limit 1";
List<OrderDTO> orders = jdbcTemplateObject.query(getOrderSql, new Object[] { orderNumber }, new OrderMapper());
if (orders == null || orders.isEmpty()) {
return null;
} else {
return orders.get(0);
}
}
}
This is the class where the JNDI connection bean is manually instantiated:
public class DataDelegateImpl {
public OrderDTO getOrder(String orderNumber, String envToUse) {
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
DatabaseMapper2Impl x = (DatabaseMapper2Impl) context.getBean("databaseMapper2Impl");
return x.getOrder(orderNumber, envToUse);
}
}
In order for Spring to manage the instantiation and injection of your DatabaseMapper2Implbean, you will have to create an ApplicationContext, and declare the bean in that context, exactly as you have done.
If the question is just how to avoid using XML for that declaration, you could annotate DatabaseMapper2Impl with #Component and instead use
ApplicationContext context = new AnnotationConfigApplicationContext(DatabaseMapper2Impl.class);
to create the context.
If you really need to have the DatabaseMapper2Impl #Autowired into an instance of DataDelegateImpl, then that instance would also have to be controlled by Spring, so you'd have to create the context at a higher level and make the DataDelegateImpl a bean as well.
Related
so I'm trying to run a sql query within this java app. I think I have the DAO set up correctly but it can't find the XML file which contains my queries. The code in question for my DAO implementation is:
private Properties queries;
public void setQueries(Properties queries) {
this.queries = queries;
}
public Boolean checkAssigned(String Id) {
String sql = queries.getProperty("CHECK_IF_ASSIGNED");
Map<String,Object> params = new HashMap<>();
List<String> assignedList;
params.put(":Id",Id);
LOG.info("Checking to see if already assigned \n" + "sql=" + sql
+ "\n" + "params=" + params);
assignedList = getNamedParameterJdbcTemplate().query(sql,params,
new assignedMapper());
if (assignedList == null || assignedList.size() == 0) {
ScreenVo.setSwitch(false);
}
else {
ScreenVo.setSwitch(true);
}
return ScreenVo.getSwitch();
}
My DAO is just:
public interface ScreenDao {
Boolean checkAssigned(String Id);
}
My queries.xml file looks like:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<util:properties id="queries">
<prop key="CHECK_IF_ASSIGNED">
<![CDATA[
--Long query
]]>
</prop>
</util:properties>
</beans>
The bean for the dao in the applicationContext.xml is:
<bean id="screenDaoImpl" class="com.corp.apps.actionator.dao.ScreenDaoImpl">
<property name="dataSource" ref="datasource"/>
<property name="queries" ref="queries"/>
</bean>
And my declaration of the queries file in the applicationContext is:
<import resource="classpath:queries.xml"/>
It's declared in my web.xml in a similar fashion.
I tried to include everything that could possibly be relevant. I've tried autowiring the bean in ScreenDaoImpl.java but that didn't work. I'm really not sure where to go from here, or what I might have done wrong.
EDIT:
The exception I'm getting is:
javax.faces.event.MethodExpressionActionListener.processAction java.lang.NullPointerException
And my screenDaoImpl is declared before use as:
private static ScreenDao screenDao = new ScreenDaoImpl();
Spring-Bean screenDaoImpl must be created through Spring context, in this case Spring can inject required properties (dataSource and queries) in created bean.
I don't know your architecture of application. But I can offer you a couple of ways.
1 - If you want use screenDaoImpl in spring-bean which declared in spring-xml then you can do it like this:
<bean id="screenServiceImpl" class="com.corp.apps.actionator.service.ScreenServiceImpl">
<property name="screenDao" ref="screenDaoImpl"/>
</bean>
The better way is make all your application in Spring. And create (and inject) beans by spring-context xml. Do not create bean-objects by new. Spring can not inject properties in these objects.
If it is difficult then try to find examples of applications on the Spring site. Maybe try spring-boot (without xml).
2 - If you want use screenDaoImpl in non-spring object you can get screenDaoImpl from spring-context by "bridge". Create class:
package com.corp.apps.actionator.util;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class AppSpringBridge implements ApplicationContextAware {
private static ApplicationContext context;
public void setApplicationContext(ApplicationContext context) throws BeansException {
this.context = context;
}
public static ApplicationContext getApplicationContext() {
return context;
}
}
Define bean in application-context.xml:
<bean id="springBridge" class="com.corp.apps.actionator.util.AppSpringBridge />
Spring create this bean, but method getApplicationContext() (and context property) of this bean is static. And we can use getApplicationContext() in any methods:
ScreenDao screenDao = (ScreenDao)AppSpringBridge.getApplicationContext().getBean("screenDaoImpl");
I fixed it, and for posterity's sake I'll post my solution here:
First I autowired my screenDao bean in the invoking class, and then I created a static method to set screenDao.
#Autowired
private static ScreenDao screenDao;
#PostConstruct
public static void setScreenDao(ScreenDao newScreenDao) {
screenDao = newScreenDao;
}
#PostConstruct
public ScreenDao getScreenDao() {
return screenDao;
}
I'm not really sure if getScreenDao does anything but I added it as well.
Then in my application context I created a bean I called initialize to invoke the static method.
<bean id="initialize" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass" value="com.corp.apps.consolidator.backing.ScreenBean"/>
<property name="targetMethod" value="setScreenDao"/>
<property name="arguments">
<list>
<ref bean="screenDao"/>
</list>
</property>
</bean>
These two changes resolved my issue.
I'm learning about spring data and because I'm also learning about kotlin so I decided to work with kotlin during spring learning. So I want to ask how we can Implement setter dependency injection in kotlin? as in Java we can that as below.
#Component
public class StudentDaoImp {
public DataSource dataSource;
public JdbcTemplate jdbcTemplate;
public DataSource getDataSource() {
return dataSource;
}
#Autowired
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
public JdbcTemplate getJdbcTemplate() {
return jdbcTemplate;
}
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
}
And here is my spring.xml file.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.h2.Driver" />
<property name="url" value="jdbc:h2:~/test" />
</bean>
<context:component-scan base-package="com.package.*" />
</beans>
Then I tried it in kotlin.
#Component
class StudentDao {
#Autowired
lateinit var dataSource: DataSource
var jt = JdbcTemplate(dataSource)
}
Then I'm getting the exception.
Caused by: kotlin.UninitializedPropertyAccessException: lateinit
property dataSource has not been initialized
I know about this exception because I'm using dataSource before autowired happen. So I have also tried this.
#Autowired
fun setDataSource(dataSource: DataSource) {
this.jt = JdbcTemplate(dataSource)
}
This is also an error, because JVM already have that signature behind the scene.
So how I can Initialize JdbcTemplate with the dataSourceparameter?
Note: I only want Code side example/solution. I know about the XML solution.
like in Java you can't use properties that are injected after instantiation at instantiation time. In Java you'd get a NullPointerException when you would do the equivalent, e.g.
#Autowired
private Datasource datasource;
private JdbcTemplate jt = new JdbcTemplace(dataSource);
But you can let Spring call a method of your choice after it has injected everything:
lateinit var jt: JdbcTemplate
#PostConstruct
fun initAfterAutowireIsDone() {
jt = JdbcTemplate(dataSource)
}
There is also the InitializingBean interface that can be used instead of the annotation. The same works in Java.
The other option you have in Kotlin is to use a lazy property when you ensure you don't access it at instantiation time.
val jt: JdbcTemplate by lazy { JdbcTemplate(dataSource) }
While I consider zapl answer correct, I would also suggest you to consider constructor arguments injection:
#Component
class StudentDao #Autowired constructor(
private val dataSource: DataSource
) {
private val jt = JdbcTemplate(dataSource)
}
In this way you can obtain non modifiable variables without warning about late initialization.
Also, if you need dataSource variable only to initialize jt, you can remove val key from constructor.
I am working on this Spring MVC project where I have trouble getting this Dao class auto wired in the controller through an Interface that is implemented by the Dao. This is portion of my spring-config.xml. I am using aspectJ, Annotation and TX management.
<aop:aspectj-autoproxy />
<context:component-scan base-package="com.simulator" />
<context:annotation-config />
<tx:annotation-driven />
<context:property-placeholder
location="classpath*:config.properties" />
<bean id="oidDao" class="com.simulator.service.OidDao">
<property name="ipaddressNC" value="${ipaddressNC}" />
<property name="ipaddressOM" value="${ipaddressOM}" />
</bean>
Dao class:
#Component
public class OidDao implements OidManager {
#Autowired
private SessionFactory sessionFactory;
private String ipaddressNC;
private String ipaddressOM;
public String getIpaddressNC() {
return this.ipaddressNC;
}
public void setIpaddressNC(String ipaddressNC) {
this.ipaddressNC = ipaddressNC;
}
public String getIpaddressOM() {
return ipaddressOM;
}
public void setIpaddressOM(String ipaddressOM) {
this.ipaddressOM = ipaddressOM;
}
OidManager:
public interface OidManager {
public String getIpaddressNC();
public String getIpaddressOM();
}
Controller:
#Controller
public class HomeController {
#Autowired
OidManager oim;
#RequestMapping(value = "/", method = RequestMethod.GET)
public String indexpage(ModelMap modelMap) {
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {"spring-config.xml"});
o = (OidManager)context.getBean("oidDao");
o.getIpaddressNC(); // ---> this returns data read from ext properties file and works fine
oim.getIpaddressNC(); // ---> this returns null`
I am trying to re-use the Dao, hence I dont want to call the ApplicationContext multiple times from each method. What am I doing wrong? If I make the variables getIpaddressNC, getIpaddressOM static, then auto wiring works, if not oim returns null though the variables are initialized via setters on application load.
You used both Component Scanning and Manual Wiring for OidDao. You defined oidDao in xml config, as follows:
<bean id="oidDao" class="com.simulator.service.OidDao">
<property name="ipaddressNC" value="${ipaddressNC}" />
<property name="ipaddressOM" value="${ipaddressOM}" />
</bean>
Then, added a Component annotation on OidDao, as follows:
#Component
public class OidDao implements OidManager {
...
}
Drop the Component annotation and you'll be fine, i guess! Because otherwise, <context:component-scan base-package="com.simulator" /> will pick OidDao and instantiate an instance from it with default constructor and without calling your setters.
You are using #Component annotation + you have also defined a bean. Therefore actually two beans are created. One created due to use of #Component would have the properties set to 'null'. This is expected since you are not setting the properties to any value. Either remove #Component annotation and use 'autowire-candidate="true"' property on bean definition or else remove the bean definition in XML and use relevant annotation on the class to set properties to correct values from property file.
Change your bean definition to:
<bean id="oim" class="com.simulator.service.OidDao">
<property name="ipaddressNC" value="${ipaddressNC}" />
<property name="ipaddressOM" value="${ipaddressOM}" />
</bean>
Let this create bean with id oim which can be set to the property oim in your Controller.
I'm experimenting with spring-security for authentication and want to be able to add users at runtime. I figured using UserDetailsManager would be minimally intrusive. How do I make it available as a bean, so that I can access it in controllers and other objects?
The Code I was starting with is as follows:
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth, DataSource dataSource, PasswordEncoder enc) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource).withDefaultSchema().passwordEncoder(enc)
.withUser("user").password(enc.encode("password")).roles("USER").and()
.withUser("admin").password(enc.encode("password")).roles("USER", "ADMIN");
}
jdbcAuthentication() creates a JdbcUserDetailsManager, everything works fine. But I don't know to how to access that after the web app's initialization. I tried two variants that didn't work:
#Bean
public UserDetailsManager userDetailsManager(DataSource dataSource,PasswordEncoder enc) throws Exception {
return new JdbcUserDetailsManagerConfigurer<>().dataSource(dataSource).withDefaultSchema().passwordEncoder(enc)
.withUser("user").password(enc.encode("password")).roles("USER").and()
.withUser("admin").password(enc.encode("password")).roles("USER", "ADMIN").and()
.getUserDetailsService();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth, UserDetailsManager userDetailsManager) throws Exception {
auth.userDetailsService(userDetailsManager);
}
When filling out the login form, I get the following:
Table "USERS" not found; SQL statement:
select username,password,enabled from users where username = ? [42102-185]
So it seems that this does not initialize the bean properly. Second try:
#Bean
public UserDetailsManager userDetailsManager(AuthenticationManagerBuilder auth, DataSource dataSource, PasswordEncoder enc) throws Exception {
return auth.jdbcAuthentication().dataSource(dataSource).withDefaultSchema().passwordEncoder(enc)
.withUser("user").password(enc.encode("password")).roles("USER").and()
.withUser("admin").password(enc.encode("password")).roles("USER", "ADMIN").and()
.getUserDetailsService();
}
During initialization, I get:
java.lang.IllegalStateException: Cannot apply ...JdbcUserDetailsManagerConfigurer#3bd97b0d to already built object
So using the builder in an #Bean method does not work either.
jdbcAuthentication() does more than just creating a JdbcUserDetailsManagerConfigurer; most importantly, it registers the configurer using apply(), so that all configurations can later be executed in the right order.
Luckily, apply() is public, so we can call it ourselves. Knowing that, we can move the main configuration load back into configureGlobal, using the configurer's alternate constructor. What worked for me in the end is the following:
#Bean
public JdbcUserDetailsManager userDetailsManager(DataSource dataSource) {
JdbcUserDetailsManager mgr = new JdbcUserDetailsManager();
mgr.setDataSource(dataSource); // (1)
return mgr;
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth, JdbcUserDetailsManager userDetailsManager, DataSource dataSource, PasswordEncoder enc) throws Exception {
//set user detail service manually
auth.userDetailsService(userDetailsManager);
JdbcUserDetailsManagerConfigurer<AuthenticationManagerBuilder> conf =
new JdbcUserDetailsManagerConfigurer<>(userDetailsManager);
//apply the configurer
auth.apply(conf);
conf.dataSource(dataSource) // (2)
.withDefaultSchema().passwordEncoder(enc)
.withUser("user").password(enc.encode("password")).roles("USER").and()
.withUser("admin").password(enc.encode("password")).roles("USER", "ADMIN");
}
It seems that setting the data source in (1) and (2) is redundant, but leaving either one out results in an exception during initialization:
//without (1)
java.lang.IllegalArgumentException: 'dataSource' or 'jdbcTemplate' is required
//without (2)
java.lang.IllegalStateException: DataSource must be set
The first error is the validation of the bean returned by userDetailsManager(), the second that of the configurer before it is executed by the AuthenticationManagerBuilder.
Configured like this, I can write, e.g. in a controller:
#Autowired
private UserDetailsManager users;
#Autowired
private PasswordEncoder enc;
#RequestMapping(...)
public String handle(Model model) {
users.createUser(new User(username, enc.encode(password), authorities);
return "view";
}
If i got you right, you want to create a bean that handles users, i would suggest declaring it in the spring.xml and using functions that keep adding to the bean.
try using an applicationcontext, this will be on main page
ApplicationContext ac;
ac=new ClassPathXmlApplicationContext("Spring.xml");
prisontest par=(prisontest)ac.getBean("prison");
here, applicationcontext is like a container holding beans and prisontest is class that defines the datasource, u can understand seeing the spring.xml,
the spring.xml will look in this way:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="prison" class="prisontest">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost/tgmc" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
</beans>
and the bean that refers to the datasource will be like this:
public class prisontest {
DataSource ds;
public void setDataSource(DataSource ds)
{
this.ds=ds;
}
add your code here for managing users on runtime
}
you can also put your other code in the same class, hope this helps.
I am writing a class that implements the following method:
public void run(javax.sql.DataSource dataSource);
Within this method, I wish to construct a Spring application context using a configuration file similar to the following:
<bean id="dataSource" abstract="true" />
<bean id="dao" class="my.Dao">
<property name="dataSource" ref="dataSource" />
</bean>
Is it possible to force Spring to use the DataSource object passed to my method wherever the "dataSource" bean is referenced in the configuration file?
I have been in the exact same situation. As nobody proposed my solution (and I think my solution is more elegant), I will add it here for future generations :-)
The solution consists of two steps:
create parent ApplicationContext and register your existing bean in it.
create child ApplicationContext (pass in parent context) and load beans from XML file
Step #1:
//create parent BeanFactory
DefaultListableBeanFactory parentBeanFactory = new DefaultListableBeanFactory();
//register your pre-fabricated object in it
parentBeanFactory.registerSingleton("dataSource", dataSource);
//wrap BeanFactory inside ApplicationContext
GenericApplicationContext parentContext =
new GenericApplicationContext(parentBeanFactory);
parentContext.refresh(); //as suggested "itzgeoff", to overcome a warning about events
Step #2:
//create your "child" ApplicationContext that contains the beans from "beans.xml"
//note that we are passing previously made parent ApplicationContext as parent
ApplicationContext context = new ClassPathXmlApplicationContext(
new String[] {"beans.xml"}, parentContext);
I discovered two Spring interfaces can be used to implement what I need. The BeanNameAware interface allows Spring to tell an object its name within an application context by calling the setBeanName(String) method. The FactoryBean interface tells Spring to not use the object itself, but rather the object returned when the getObject() method is invoked. Put them together and you get:
public class PlaceholderBean implements BeanNameAware, FactoryBean {
public static Map<String, Object> beansByName = new HashMap<String, Object>();
private String beanName;
#Override
public void setBeanName(String beanName) {
this.beanName = beanName;
}
#Override
public Object getObject() {
return beansByName.get(beanName);
}
#Override
public Class<?> getObjectType() {
return beansByName.get(beanName).getClass();
}
#Override
public boolean isSingleton() {
return true;
}
}
The bean definition is now reduced to:
<bean id="dataSource" class="PlaceholderBean" />
The placeholder receives its value before creating the application context.
public void run(DataSource externalDataSource) {
PlaceholderBean.beansByName.put("dataSource", externalDataSource);
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
assert externalDataSource == context.getBean("dataSource");
}
Things appear to be working successfully!
The second solution causes an exception because of a refresh problem. A more elegant way will be adding objects to the context and then loading xml definitions using the xmlreader.
Thus:
ObjectToBeAddedDynamically objectInst = new ObjectToBeAddedDynamically();
DefaultListableBeanFactory parentBeanFactory = new DefaultListableBeanFactory();
parentBeanFactory.registerSingleton("parameterObject", objectInst);
GenericApplicationContext parentContext = new GenericApplicationContext(parentBeanFactory);
XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(parentContext);
xmlReader.loadBeanDefinitions(new FileSystemResource("beandefinitions.xml"));
parentContext.refresh();
ObjectUsingDynamicallyAddedObject userObjectInst= (ObjectUsingDynamicallyAddedObject )parentContext.getBean("userObject");
and
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userObject" class="com.beanwiring.ObjectUsingDynamicallyAddedObject"
>
<constructor-arg ref="parameterObject" />
</bean>
</beans>
works perfect!
You can create a wrapper class for a DataSource that simply delegates to a contained DataSource
public class DataSourceWrapper implements DataSource {
DataSource dataSource;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
#Override
public Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
#Override
public Connection getConnection(String username, String password)
throws SQLException {
return dataSource.getConnection(username, password);
}
//delegate to all the other DataSource methods
}
Then in you Spring context file you declare DataSourceWrapper and wire it into all your beans. Then in your method you get a reference to DataSourceWrapper and set the wrapped DataSource to the one passed in to your method.
This all working is highly depended on what happens in your Spring context file when its being loaded. If a bean requires the DataSource to already be available when the context loads then you may have to write a BeanFactoryPostProcessor that alters the Spring context file as it loads, rather then doing things after the load (though perhaps a lazy-init could solve this issue).
If you create an object by calling "new", it's not under the control of the Spring factory.
Why not have Spring inject the DataSource into the object instead of passing it into run()?
There's a more elegant way in which you can use an external xml file and load it with file system resource then inject beans configured in it into your application context. Thus:
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.FileSystemResource;
import org.springframework.stereotype.Service;
#Service
#Order(-100)
public class XmlBeanInitializationService implements ApplicationContextAware, InitializingBean {
private ApplicationContext applicationContext;
#Value("${xmlConfigFileLocation}")
private String xmlConfigFileLocation;
#Override
public void afterPropertiesSet() throws Exception {
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader((BeanDefinitionRegistry)applicationContext);
reader.loadBeanDefinitions(new FileSystemResource(xmlConfigFileLocation));
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
where ${xmlConfigFileLocation} is a property specified in your application.properties file which points to the file location in your system thus:
xmlConfigFileLocation="your-file-path-anywhere-in-your-system"
and your xml file may contain:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="com.yourpackage.YourBean1Class"></bean>
<bean class="com.yourpackage.YourBean2Class"></bean>
<bean class="com.yourpackage.YourBean3Class"></bean>
</beans>
thus when your application starts spring loads the class and loads the bean into application context.
Hope this helps someone.