Use Spring Bean in Non-Spring Bean container class - spring

Suppose I have a couple different datasources defined as spring beans:
<bean id="dataSource1" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost/db1?user=root&password=password" />
</bean>
<bean id="dataSource2" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost/db2?user=root&password=password" />
</bean>
Now I'd like to use one of these datasource beans but from a non-spring bean container. I could call appContext.getBean("dataSource1") but I've read that's bad practice since it creates an explicit dependency on the spring framework in your code. Is there are better way to accomplish this in a way that is not implementation specific? Perhaps something like DatasourceFactory.getInstance("datasource1")?
Is this a weird request? I realize this would be very easy if the container class was a Spring bean since I could just use standard dependency injection in that case. But this is something I've been curious about. It seems that using dependency injection creates an endless loop, where if you want to use a spring bean in a class then that class must also be a bean, and then if another class wants to use that bean then it must also be a bean, and so on, and so on. I don't see an elegant way to break the dependency injection chain.
Again, maybe it's not necessary to break the chain, maybe the answer is that you do make all your classes spring beans, but I was just curious.
Can service locator pattern be applied here? If so can someone provide an example? Thanks.

The method you describe is the classic way to do it.
public class UnmanagedBean {
public UnmanagedBean(DataSource dataSource) {
... // do something
}
}
...
ApplicationContext context = ...;
DataSource dataSource2 = context.getBean("dataSource2");
UnmanagedBean bean = new UnmanagedBean(dataSource2);
You can add a level of abstraction with a BeanProvider class that does this for you, but you are limited to getting the beans directly from the ApplicationContext.

Related

Spring injecting one reference bean into another reference bean

In the below spring configuration snippet, injecting reference of "SomeManager" into bean "SomeWorker" and "SomeLocal". The reference of "SomeLocal" is also injected into "SomeWorker".
My doubt is is it possible to inject the same reference of "SomeManager" injected into "SomeWorker" into another bean, like here in "SomeLocal".
Problem is if i inject it separately into "SomeWorker" and "SomeLocal" than unnecessarily there will be two instances of "SomeManager" which is basically not required in this scenario as "SomeLocal" is referred only within the "SomeWorker"
<bean id="SomeWorker" class="com.test.worker.SomeWorker">
<property name="someManager" ref="SomeManager" />
<property name="someLocal" ref="SomeLocal"/>
<bean id="SomeLocal" class="com.test.local.SomeLocal">
<property name="someManager" ref="SomeManager" />
</bean>
<bean id="SomeManager" class="com.test.manager.SomeManager"/>

How to guarante Spring PropertyPlaceHolder been loaded before specified bean been generated?

I am working with Spring 3.2 and I am trying to define some beans with property place holders.
<context:property-placeholder location="classpath*:/config/db2.properties"/>
<bean id="testBean" class="com.mywork.func.service.TestBean">
<property name="driverClassName" value="${jdbc.driver}" />
...
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driver}" />
...
</bean>
In the db.properties, I have
jdbc.driver=oracle.jdbc.driver.OracleDriver
As the two beans listed in the snippet are both defined with placeholders like "${jdbc.driver}", but I got different things for the properties in beans:
for the testBean I got "oracle.jdbc.driver.OracleDriver" while in dataSource I got "${jdbc.driver}".
Some testing show that the "datasource" was init before the property-placeholder been initializated property while "testBean" was init after that.
Could anyone give me some clues how to ensure the property placeholder been initialized as early to to ensure any other beans I expected to utilize the property place holders can got proper values?
There was a question almost the same as mine, but with no effective answer to it.
How to guarantee Spring bean order? PropertyPlaceHolder issue

Spring bean creation

Is it possible to create to bean with same id with same class with different property in spring ? Like:
<bean id ="a" class= "com.tofek.A"
<property message = "khan"/>
</bean>
<bean id = "a" class = "com.tofek.A"
<property message="tofek"/>
</bean>
As per my understanding it will create, but while fetching the bean using getBean() method it will give exception like NoBeanDefinitionFoundException.
Please correct my understanding if I'm wrong?
Make sure your spring context is loaded sucessfully.
Answering your question. You can have two identical bean definitions in two different sprintContext configurations.
The bean from second context will override bean created by first one.
For example :
context1.xml
<bean id="bean1" class="org.springframework.beans.TestBean"/>
context2.xml
<bean id="bean1" class="org.springframework.beans.TestBean"/>
then, the bean from context2.xml will override bean created by contex1.xml.
It of course depends on order of creating spring contexts. The laters overrides the ones made before.
You can use getBean() to fetch bean by type or name. In this case, both bean have same id's and types, the spring wouldn't know which one you want to fetch.

Create a Guava TypeToken in Spring xml config?

I'd like to be able to inject Guava TypeToken objects by specifying them as a bean in a Spring xml configuration. Is there a good way to do this? Has anyone written any cade/library to make this easier?
TypeToken seems to work by using reflection to introspect its generic types and is thus constructed using an anonymous class like:
new TypeToken<List<String>>() {}
Spring's xml config syntax doesn't seem to accept generics at all, presumably because it's built at runtime and doesn't "need" them (since generics are compile time checks and technically erased at runtime).
So the only way I know to instantiate a TypeToken bean is to do it in java:
TokenConfig.java:
#Configuration
public class TokenConfig {
#Bean
public TypeToken<List<String>> listOfStringsToken() {
return new TypeToken<List<String>>() {};
}
}
system-test-config.xml:
<beans>
<context:annotation-config/>
<bean class="com.acme.TokenConfig"/>
<bean class="com.acme.Consumer">
<property name="typeToken" ref="listOfStringsToken"/>
</bean>
</beans>
Is there a way to do this with just an xml config?
Maybe you can use spring FactoryBeans: look for factory methods at http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/beans.html
To answer my own question:
It IS possible to create a non-generic TypeToken using the static constructor TypeToken.of(Class), but this wont work for deeper generic types.
Here's the Spring xml config:
<bean class="com.google.common.reflect.TypeToken" factory-method="of">
<constructor-arg type="java.lang.Class" value="java.lang.Integer" />
</bean>
Which is equivelent to:
TypeToken.of(Integer.class)
and
new TypeToken<Integer>() {}
I also found a way to use the TypeToken.of(Type) constructor with a ParameterizedType constructed using Google Guice's Types utility. Guava has one too, but it's not public. :'(
I'm not sure if this is quite as robust as using TypeToken/TypeCapture, but it seems to work. Unfortunately it's pretty ugly and long... (maybe someone can simplify it?)
<bean class="com.google.common.reflect.TypeToken" factory-method="of">
<constructor-arg index="0">
<bean class="com.google.inject.util.Types" factory-method="newParameterizedType">
<constructor-arg index="0">
<value type="java.lang.Class">java.util.List</value>
</constructor-arg>
<constructor-arg index="1">
<array><value type="java.lang.Class">java.lang.String</value></array>
</constructor-arg>
</bean>
</constructor-arg>
</bean>
Which is equivelent to:
new TypeToken<List<String>() {}

I still don't get how to avoid the use of getBean()

I'm new to Spring and I've read many guides on how to inject beans. Curiously, in every example I see, they use getBean in a class main method (not what I need). Also I've read many forums and questions related to how not to use getBean but I still can't figure out the best approach for my app.
I'm refactoring a web app that is highly coupled and without design patterns. Every business class has a corresponding DAO class, every DAO class extends a super DAO which handles the connection and other stuff. The problem here is that every DAO needs, in the constructor, some database config parameters that are being passed from the business class. What I'm trying to do is to put these parameters in a DBConfig bean and inject them into every DAO allowing me to create the DAO object from every business class simply, for example: dao = new myDAO().
How can I inject the DBConfig bean into every DAO "automatically"? Should I use getBean in the super DAO?
Your config could look like this:
<bean id="daoConfig1" class="com.foo.dao.DAOConfig">
<property name="dbUrl" value="jdbc://urlForDao1" />
...
</bean>
<bean id="dao1" class="com.foo.dao.DAO1">
<constructor-arg ref="daoConfig1" />
</bean>
<bean id="business1" class="com.foo.service.Business1">
<property name="dao" ref="dao1" />
</bean>
<bean id="daoConfig2" class="com.foo.dao.DAOConfig">
<property name="dbUrl" value="jdbc://urlForDao2" />
...
</bean>
<bean id="dao2" class="com.foo.dao.DAO2">
<constructor-arg ref="daoConfig2" />
</bean>
<bean id="business2" class="com.foo.service.Business2">
<property name="dao" ref="dao2" />
</bean>
Or share a single daoConfig instance between all daoX beans, if that's what you want.
You can then use the folowing to handle the business logic:
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"beans.xml"});
Business1 b1 = (Business1) context.getBean("business1");
b1.doStuff();
Or better still, use something like Spring MVC that can wire the business beans into your controllers without needing to call getBean().

Resources