1. Use factory-method and cheat spring.
2. Static injection using @Aurtowired:
What that article doesn't mention, and the key benefit in my project, is that when you use @AutoWired, you can have the Spring-invoked initialization method marked as private, to avoid polluting your public API.
Spring config:
Java class with static field:
This is a big improvement over my previous unsatisfactory solution, which was to use org.springframework.beans.factory.config.MethodInvokingFactoryBean with a public method on StaticHub like this:
You can also use @Qualifier to disambiguate if you have multiple beans in your Spring container which implement MyInterface:
Before you use this, consider carefully whether static fields are actually a good idea - in general this kind of pattern is something Spring is designed to help you avoid!
In my project there are good reasons for it, but it needs thought - things get complicated quickly in environments with multiple classloaders, or with multiple Spring containers inside the same classloader; it also makes it harder to use newfangled clustering technologies which let you scale to multiple JVMs.
Well, may be this option is not quite right in srping terms but, this work for me, and at last i have got only one instance in my context.
Set static properties in a static factory method.
i mean set in appContext.xml as follows
The interest thing is in factory method and the argument.Code:<bean id="properties" class="org.springframework.beans.factory.config.PropertiesFactoryBean"> <property name="location" value="classpath:/a/property/file/Utils.properties" /> </bean> <bean class="your.class.UtilMessages" factory-method="setInstance" autowire="autodetect" scope="singleton"> <constructor-arg ref="properties" /> </bean>
So the class looks like...
I did call it "setInstance" because i'm setting the value, even when it's a cosntructor.Code:public class UtilMessages { public static Properties properties; // Cheating spring to set a static property. public static Properties setInstance(Properties propertiesArgs) { properties = propertiesArgs; return properties; } public static String getMsg(String key) { return properties.getProperty(key); } }
So you can set any static property in context instantantion and use them after as any static value.
For me was a property file, so i can read it by calling static UtilsMessages.getMsg("key") method. No need to set dependency in xml file and no need to create a new instance each time i need it.
2. Static injection using @Aurtowired:
What that article doesn't mention, and the key benefit in my project, is that when you use @AutoWired, you can have the Spring-invoked initialization method marked as private, to avoid polluting your public API.
Spring config:
<beans xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<!-- Scan for @Autowired annotations -->
<context:annotation-config>
<!-- The instance to be injected into the static field on StaticHub -->
<bean class="internal.stuff.MyInterfaceImpl" name="myPrecious">
<!-- The class which will have its static field set via @Autowired -->
<bean class="very.public.api.StaticHub" name="dummyInstanceOfStaticHub">
</beans>
Java class with static field:
package very.public.api; import org.springframework.beans.factory.annotation.Autowired; public final class StaticHub { private static MyInterface theStaticInstance; /** * Note this initialization method is private! No nasty public setInstance method. */ @Autowired(required = true) private StaticHub(MyInterface instance) { theStaticInstance = instance; } /** * My public API, making the Spring-created instance of MyInterface statically accessible */ public static MyInterface getInstance() { return theStaticInstance; } }
This is a big improvement over my previous unsatisfactory solution, which was to use org.springframework.beans.factory.config.MethodInvokingFactoryBean with a public method on StaticHub like this:
<bean name="staticHubInitializer" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> <property name="staticMethod" value="very.public.api.StaticHub.setInstance"/> <property name="arguments"> <list> <ref bean="myPrecious"/> </list> </property> </bean> public static void setInstance(MyInterface instance) { theStaticInstance = instance; }...which is not very pretty.
You can also use @Qualifier to disambiguate if you have multiple beans in your Spring container which implement MyInterface:
import org.springframework.beans.factory.annotation.Qualifier; ... private StaticHub(@Qualifier("myPrecious") MyInterface instance) { theStaticInstance = instance; }
Before you use this, consider carefully whether static fields are actually a good idea - in general this kind of pattern is something Spring is designed to help you avoid!
In my project there are good reasons for it, but it needs thought - things get complicated quickly in environments with multiple classloaders, or with multiple Spring containers inside the same classloader; it also makes it harder to use newfangled clustering technologies which let you scale to multiple JVMs.