If you’re a serious Java (or possibly even .NET) developer you’ve most likely used the Spring Framework before for all you dependency injection needs. You therefore probably know that there are 2 common ways to inject dependencies into your spring beans:
- setter injection
- constructor injection
But, did you know that there is a lot more to it than that? Spring has some extremely powerful capabilities that allow you to do a lot more than just call constructors and setters when creating Spring beans and injecting dependencies.
I am going to attempt to show you some ways that will allow you to create spring beans and inject dependencies in all sorts of different ways, which should let you get a lot more out of using Spring. If you’re a Spring guru then you probably won’t get anything new out of this, however everyone else should hopefully learn something new and become a much more versatile Spring developer.
Different Ways To Instantiate Beans And Inject Dependencies
The Standard Way
The simplest way is to create a bean with no dependencies using a default constructor:
<bean class="my.crazy.example.SampleBean" id="sampleBean" />
To inject some dependencies we can use setter injection, constructor injection or a mix of both. If our SampleBean is:
public class SampleBean { private int intValue; private float floatValue; public SampleBean(int value) { intValue = value; } public void setIntValue(int value) { intValue = value; } public void setFloatValue(float floatValue) { this.floatValue = floatValue; } }
The Spring configuration could be something like:
<bean class="my.crazy.example.SampleBean" id="sampleBean"> <constructor-arg value="25" /> <property value="0.57" name="floatValue"></property> </bean>
All pretty standard stuff, on to more interesting things we go.
Using A Static Factory Method
We can use the ‘factory-method’ attribute to tell spring to call a static factory method to instantiate our bean. So, if we have a SampleBean:
public class SampleBean { public SampleBean() { } }
and a SampleBeanFactory with a static method:
public class SampleBeanFactory { public static SampleBean createEmptySampleBean() { return new SampleBean(); } }
we can do the following:
<bean id="sampleBean" class="my.crazy.example.SampleBeanFactory" factory-method="createEmptySampleBean"/>
This will only create a simple bean with no dependencies and what if we want to pass parameters to our factory method? Simple, if our SampleBean is now:
public class SampleBean { private int intValue; private float floatValue; public SampleBean() { } public void setIntValue(int value) { intValue = value; } public void setFloatValue(float floatValue) { this.floatValue = floatValue; } }
and our SampleBeanFactory is:
public class SampleBeanFactory { public static SampleBean createSampleBeanWithIntValue(int value) { SampleBean sampleBean = new SampleBean(); sampleBean.setIntValue(value); return sampleBean; } }
We can create a bean in the following way:
<bean id="sampleBean" class="my.crazy.example.SampleBeanFactory" factory-method="createSampleBeanWithIntValue"> <constructor-arg value="25"/> <property name="floatValue" value="0.57"/> </bean>
The constructor arguments will be passed as parameters to our static factory method and the property elements will be set on the SampleBean. Obviously you can’t use setter injection to inject parameters into the factory method and you can’t use constructor injection to inject dependencies into the SampleBean.
You can see how this would come in useful, especially if you’re working with existing code that you can’t change that uses static factory methods to create objects. You can now wire in objects created by static factory methods as spring dependencies. But what if the factory methods are not static, but still create objects that you want to wire in?
Using An Instance Factory Method
We can use the ‘factory-bean’ attribute along with the ‘factory-method’ attribute to call instance factory methods to create our beans. Let’s say our SampleBean is still:
public class SampleBean { private int intValue; private float floatValue; public SampleBean() { } public void setIntValue(int value) { intValue = value; } public void setFloatValue(float floatValue) { this.floatValue = floatValue; } }
Our factory on the other hand is now a SampleBeanInstanceMethodFactory:
public class SampleBeanInstanceMethodFactory { private int uselessParameter; public SampleBean createSampleBean(int value) { SampleBean sampleBean = new SampleBean(); sampleBean.setIntValue(value); return sampleBean; } public void setUselessParameter(int uselessParameter) { this.uselessParameter = uselessParameter; } }
So, we can create our SampleBean by defining our SampleBeanInstanceMethodFactory as a bean and then using it as a value to the ‘factory-bean’ attribute:
<bean id="instanceMethodFactory" class="my.crazy.example.SampleBeanInstanceMethodFactory"> </bean> <bean id="sampleBean" factory-bean="instanceMethodFactory" factory-method="createSampleBean"> <constructor-arg value="25"/> </bean>
We can also now pass parameters to our factory when we create it and still pass parameters to our factory method and the SampleBean as well:
<bean id="instanceMethodFactory" class="my.crazy.example.SampleBeanInstanceMethodFactory"> <property name="uselessParameter" value="123"/> </bean> <bean id="sampleBean" factory-bean="instanceMethodFactory" factory-method="createSampleBean"> <constructor-arg value="25"/> <property name="floatValue" value="0.57"/> </bean>
This is all similar to what we did with the static factory method, but it gives you the extra level of flexibility to be able to work with instance methods that create objects. But what if I don’t like any of this factory method nonsense and still want to be really advanced?
Using A FactoryBean
You can instantiate objects by creating a factory class that implements Spring’s own FactoryBean interface. This means that you can treat your FactoryBean as if it were itself the object that you’re trying to create, so you would wire in the FactoryBean anywhere you want to use the actual object you’re trying to create and Spring will automatically call the right method on the FactoryBean and use the return of that method as the object. This is best demonstrated with an example. The FactoryBean interface has the following methods on it:
- Object getObject()
- Class getObjectType()
- boolean isSingleton()
You have to implement all three. So, our SampleBean is now:
public class SampleBean { public SampleBean() { } }
Our FactoryBean to create the SampleBean will look like this:
public class SampleBeanFactoryBean implements FactoryBean { public Object getObject() throws Exception { return new SampleBean(); } public Class getObjectType() { return SampleBean.class; } public boolean isSingleton() { return false; } }
When we want to wire in a SampleBean as a dependency of a FunkyBean that looks like this:
public class FunkyBean { private SampleBean sampleBean; public FunkyBean(SampleBean sampleBean) { this.sampleBean = sampleBean; } }
we would do the following:
<bean id="sampleBean" class="my.crazy.example.SampleBeanFactoryBean" /> <bean id="funkyBean" class="my.crazy.example.FunkyBean"> <constructor-arg ref="sampleBean"/> </bean>
As you can see we just wire in the SampleBeanFactoryBean in place of a SampleBean and let Spring do its magic by calling getObject() and returning the output of that as the bean to wire into the FunkyBean, pretty sweet.
Why is this useful, you ask? Well in our contrived example above it doesn’t really add much value, but let’s say you needed to create an object in some really complex fashion. For example, let’s say you obtain your object, by establishing some kind of network connection and getting some xml sent over-the-wire which you then de-serialize into your object. You then want to treat you new object as spring singleton (yeah I know, not contrived at all :)). Well, FactoryBean is a perfect way to do this. It provides you with a factory method type of approach to creating your object and then lets you easily manage your new object as a Spring singleton. So, if our SampleBean still looks like:
public class SampleBean { public SampleBean() { } }
Our SampleBeanFactoryBean would look like this:
public class SampleBeanFactoryBean implements FactoryBean { private SampleBean sampleBean; public Object getObject() throws Exception { //ignore the fact that all of this is basically pseudocode if (sampleBean == null) { NetworkConnection connection = NetworkConnectionFactory.getFunkyNetworkConnection(); String beanAsXml = connection.getSampleBeanAsXml(); sampleBean = DeSerializer.deserialize(beanAsXml); } return sampleBean; } public Class getObjectType() { return SampleBean.class; } public boolean isSingleton() { return true; } }
We would be able to wire in our SampleBean in exactly the same way as before. Ultra useful, but you have to implement a Spring interface which couples your code to Spring somewhat, that’s the price of power. So, consider carefully, if you don’t mind being tied to Spring, then there is no problem, but if you want your code to remain unaware of the container you’re using, you may need to consider a different solution.
Using Lookup-Method Injection
I thought I would include this one because it is pretty cool and a good feature to be aware of. Essentially, Spring can dynamically override methods on container managed beans. This is actually explained pretty well in the Spring documentation, but here is the quick and dirty version. If you have a singleton bean (SingletonBean) that needs to work with an instance of another bean (which is not a singleton – PrototypeBean) every time a method on the singleton is invoked, you can do one of 2 things. You can either make your SingletonBean BeanFactoryAware so that you can fetch a different instance of your PrototypeBean every time your singleton needs it or you can use lookup-method injection.
The first solution is fine but is not ideal if you don’t want to tie your code to Spring, so this is where the second solution comes in. If your SingletonBean looks like this:
public abstract class SingletonBean { public Object process(String someState) { PrototypeBean prototypeBean = grabPrototypeBean(); prototypeBean.setState(someState); return prototypeBean.doPrototypeBeanStuff(); } protected abstract PrototypeBean grabPrototypeBean(); }
and your PrototypeBean is as follows:
public class PrototypeBean { private String state; public Object doPrototypeBeanStuff() { // do whatever here return ""; } public void setState(String someState) { state = someState; } }
Spring can actually override the createPrototypeBean() using lookup-method injection to provide a new instance of a PrototypeBean every time that method is called. Spring does this by using bytecode instrumentation with CGLIB to dynamically subclass the SingletonBean and provide it with an implementation for the createPrototypeBean() method (obviously you will need the CGLIB library in your classpath somewhere). The Spring configuration would be as follows:
<bean id="prototypeBean" class="my.crazy.example.PrototypeBean" scope="prototype"> </bean> <bean id="singletonBean" class="my.crazy.example.SingletonBean"> <lookup-method name="grabPrototypeBean" bean="prototypeBean"/> </bean>
You can see how this one could come in handy in some situations if you want to keep managing your beans through dependency injection but don’t want to tie your code to Spring. Plus, it sounds really impressive when you tell people how you were “using bytecode instrumentation to facilitate dynamic lookup-method injection” :).
Well, that’s it, hopefully you got something new out of this and have more of an understanding of the powerful features that you have at your disposal when you use Spring even for basic things like dependency injection.
If you would like me to expand on anything that I covered here then please let me know by leaving a comment and I will create a new post or extend this one. Also let me know if you feel like this post should have covered some more ground, perhaps more relevant examples, or possibly there is another cool way to instantiate beans in Spring?