I have a follofing situation int "super-context.xml":
<bean id="conf" class="ee.Conf"/>
<bean id="service" class="ee.Serivce">
<property name="conf" ref="conf">
</bean>
Now I want to use this "super-context.xml" in various different projects. Say "sub-context.xml" has:
<import resource="super-context.xml"/>
<bean id="subConf1" class="ee.SubConf">
<property name="confloc" value="classpath:ee/customconf1.sss" />
</bean>
<bean id="subConf2" class="ee.SubConf">
<property name="confloc" value="classpath:ee/customconf2.sss" />
</bean>
...
<bean id="subConfn" class="ee.SubConf">
<property name="confloc" value="classpath:ee/customconfn.sss" />
</bean>
ee.Conf is something as follows:
public class Conf ... {
...
public void addSubConf(Resource res) {
//configuration resolving from res
}
...
}
ee.SubConf is something as follows:
public class SubConf ... {
...
#Autowired
ee.Conf superConf;
...
public void setConfloc(Resource res) {
superConf.addSubConf(res);
}
...
}
The problem aries on context load. Beans are initialized in following order (due to ordering in context file): conf, service, subConf1, subConf2, ... subConfn
But service bean actually depends on all the subConf beans (although this can't be deducted from the context definition itself). It loads OK when import in "sub-context.xml" is added after subConf bean definitions.
Reason behind this is implementing modularity. Is it possible to force a bean to load as late as possible ("service" bean in the example) or make beans of certain type load as soon as possible ("subConf" beans in the example), since fixed ordering of beans in "sub-context.xml" partly kills the wished modularity
Or is theree a more pure way to achieve this type of modularity?
I would say that you are approaching the problem in a wrong way. The SubConf shouldn't have a dependency on the Conf to start with. Simply inject the collection of SubConf objects in your Conf object.
public class Conf {
#Autowired
private List<SubConf> subconfs;
}
That way you eliminate the need for the SubConf to call the Conf class and this will remove your circular dependency.
See the Spring reference guide for more information on autowiring.
You can use depends-on
<bean id="beanOne" class="foo.Bar" depends-on="beanTwo" />
Related
Currently I use the following method to inject properties into beans:
app.properties:
SingletonBean.valueA=this is a value
spring.xml:
<context:property-placeholder location="classpath:app.properties"/>
<context:component-scan base-package="..."/>
SingletonBean.java:
#Component
public class SingletonBean {
#Value("${SingletonBean.valueA}")
private String valueA;
}
This works great and is extremely convenient to be able to keep all my configs in a single, simple properties file. Is there any way I could extend this to work with multiple Beans of the same class? I need to do the following, with the 2 beans having different properties:
#Autowired private SampleBean beanA;
#Autowired private SampleBean beanB;
I know I can use the #Qualifier(name=...) annotation to support the following xml:
<bean id="beanA" class="SampleBean">
<property name="key1" value="A1"/>
<property name="key2" value="A2"/>
</bean>
<bean id="beanB" class="SampleBean">
<property name="key1" value="B1"/>
<property name="key2" value="B2"/>
</bean>
But with this I am forced to use old style setters in my SampleBean class, where I would prefer to use the newer #Value annotations.
Anyone know of a way to accomplish what I want that remains most consistent with how I am currently injecting my other beans?
The simple solution is just to inject all of the properties into the bean that utilizes the 2 SampleBean instances and create them with new instead. In my real code however there are actually 3 instances, each with 15 or so properties. This is much more cruft and repetition than I would like.
I'm having some problems understanding how to use annotations, especially with beans.
I have one component
#Component
public class CommonJMSProducer
And I want to use it in another class and i thought I could do that to have a unique object
public class ArjelMessageSenderThread extends Thread {
#Inject
CommonJMSProducer commonJMSProducer;
but commonJMSProducer is null.
In my appContext.xml I have this :
<context:component-scan base-package="com.carnot.amm" />
Thanks
You have to configure Spring to use this autowiring feature:
<context:annotation-config/>
You can find the details of annotation-based config here.
ArjelMessageSenderThread also have to be managed by Spring otherwise it won't tamper with its members since it does not know about it.
OR
if you cannot make it a managed bean then you can do something like this:
ApplicationContext ctx = ...
ArjelMessageSenderThread someBeanNotCreatedBySpring = ...
ctx.getAutowireCapableBeanFactory().autowireBeanProperties(
someBeanNotCreatedBySpring,
AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT, true);
OR
as others pointed out you can use annotations to use dependency injection on objects which are not created by Spring with the #Configurable annotation.
It depends on how you create instances of ArjelMessageSenderThread.
If ArjelMessageSenderThread is a bean that should be created by spring you just have to add #Component (and make sure the package is picked up by the component scan).
However, since you extend Thread, I don't think this should be a standard Spring bean. If you create instances of ArjelMessageSenderThread yourself by using new you should add the #Configurable annotation to ArjelMessageSenderThread. With #Configurable dependencies will be injected even if the instance is not created by Spring. See the documentation of #Configurable for more details and make sure you enabled load time weaving.
I used XML instead of annotations. This seemed difficult for not a big thing. Currently, I just have this more in the xml
<bean id="jmsFactoryCoffre" class="org.apache.activemq.pool.PooledConnectionFactory"
destroy-method="stop">
<constructor-arg name="brokerURL" type="java.lang.String"
value="${brokerURL-coffre}" />
</bean>
<bean id="jmsTemplateCoffre" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory">
<ref local="jmsFactoryCoffre" />
</property>
</bean>
<bean id="commonJMSProducer"
class="com.carnot.CommonJMSProducer">
<property name="jmsTemplate" ref="jmsTemplateCoffre" />
</bean>
And another class to get the bean
#Component
public class ApplicationContextUtils implements ApplicationContextAware {
Thanks anyway
I am having difficulty understanding why something in Spring Java Config using #Autowired does not work.
First, I am trying to move all my #Autowired annotations in the Java Config classes. This has the effect of making my "POJOs" back into real POJOs. I can then not only test them easily outside of a Spring context, but can also use mock objects easily and readily.
So I first tried this:
#Configuration
public class Module3ConfigClass {
#Autowired
private Module1Bean1 module1Bean1;
#Autowired
private Module2Bean1 module2Bean1;
#Bean
public Module3Bean1 module3Bean1() {
return new Module3Bean1(module1Bean1, module2Bean1);
}
}
However, when the Module3Bean1 constructor is invoked, both passed in Beans are null. If you didn't follow my made up naming convention above, both of those beans would be created by a separate Java Config configuration file. Also note that everything is wired up correctly - I know this because everything works perfectly when the #Autowired tags are on the corresponding private member fields inside of Module3Bean1.
FWIW, I tried adding an #DependsOn annotation to module3Bean1() method, but had the same results. I guess I just would really like to understand this behavior, is it correct (I suspect it is, but why)?
Finally, I found an acceptable workaround shown here:
#Configuration
public class Module3ConfigClass {
#Bean
#Autowired
public Module3Bean1 module3Bean1(Module1Bean1 module1Bean1, Module2Bean1 module2Bean1) {
return new Module3Bean1(module1Bean1, module2Bean1);
}
}
This seems fine to me, but if anyone would care to comment on it, that would be welcome as well.
I think you came across same problem I just had. In my case problem was invalid xml configuration. In my module B I had config like :
<beans>
<context:component-scan base-package="com.moduleB"/>
<import resource="classpath:applicationContext-moduleA.xml"/>
</beans>
In moduleA context I placed "context:annotation-config" annotation.
When I change import/context order to :
<beans>
<import resource="classpath:applicationContext-moduleA.xml"/>
<context:component-scan base-package="com.moduleB"/>
</beans>
Autowiring for configuration class properties started to work.
We had the same issue and came to the conclusion that the error arose because we had a circular dependency where a BeanPostProcessor was involved.
A PropertyPlaceholderConfigurer (a BeanPostProcessor) has been configured to set its propertiesArray property with the help of another bean:
<bean id="globalPropertyPlaceholderConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
lazy-init="false" depends-on="javaLoggingConfigurer">
<property name="locations">
<list>
<value>classpath:config/host/${env.instance}.properties</value>
<value>WEB-INF/config/host/${env.instance}.properties</value>
</list>
</property>
<property name="ignoreResourceNotFound" value="true" />
<property name="propertiesArray" value="#{springPropertyFinder.findProperties()}" />
</bean>
The used springPropertyFinder bean to set the propertiesArray is not a BeanPostProcessor but a "normal" bean that gathers all Properties instances with:
public Properties[] findProperties() {
Map<String, Properties> propertiesMap = applicationContext.getBeansOfType(Properties.class);
for (String title : propertiesMap.keySet()) {
PropertiesLoggerUtil.logPropertiesContent(logger, "Springcontext Properties ("+title+")", propertiesMap.get(title));
}
return propertiesMap.values().toArray(new Properties[propertiesMap.size()]);
}
The #Configuration class contained a bean of type Properties
So our assumption is that the #Configuration class has been created without being processed by the ConfigurationClassPostProcessor (also a BeanPostProcessor), because the PropertyPlaceholderConfigurer depends on the springPropertyFinder, which depends on the properties bean in the #Configuration class. The order of the BeanPostProcessors is probably not setup right under these circumstances.
This described setup worked in XML, but not with Java config.
In my application I am using ContextLoaderListener to load context files from many jars using:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:META-INF/contextBeans.xml</param-value>
</context-param>
This means I can reference beans from other jars without doing import.
In the application there are multiple deployment options and in some deployments jars can be excluded. To support that I would like some bean references to be optional. For example:
<bean id="mainAppBean" class="com.someapp.MyApplication">
<constructor-arg index="0" ref="localBean"/>
<constructor-arg index="1" ref="optionalBeanReference1"/>
<constructor-arg index="2" ref="optionalBeanReference2"/>
</bean>
In the example above I would like to have optionalBeanReference1 equal null if the reference was not found (mark it optional in some way)
Can this be done in Spring? or what method do you recommend for handling dynamic references?
My best guess is to use autowire-ing with required false. Don't know how you can express this in XML but using annotation configuration this would look like:
#Autowired(required=false)
With recent versions of Spring (tested with spring 4.1) and Java Configuration and Java 8, you can use Optional in parameters, and are only autowired if available.
#Autowired
public MyApplication(Optional<YourOptionalObject> maybeObject) {
// do something with the optional autowired
}
what method do you recommend for handling dynamic references?
I think #cristian's #Autowired answer is a good one. That will call the setter methods if the beans of that type are available. However, if you have multiple beans of the same type, I believe Spring throws an exception. If you cannot use #Autowired for this or some other reason, I see a couple of solutions:
You could make your class ApplicationContextAware and lookup the beans in the context yourself:
public void setApplicationContext(ApplicationContext applicationContext) {
if (applicationContext.containsBean("optionalBeanReference1")) {
setOptionalBeanReference1(
(OptionalBeanReference1)applicationContext.bean(
"optionalBeanReference1");
}
...
}
You could invert the dependency. Each of the optional classes could set themselves on the mainAppBean. I use this in certain situations when a direct dependency would cause loops or other problems.
<bean id="optionalBeanReference1" class="com.someapp.SomeClass">
<constructor-arg index="0" ref="mainAppBean"/>
</bean>
Then in the SomeClass:
public SomeClass(com.someapp.MyApplication mainAppBean) {
mainAppBean.setOptionalBeanReference1(this);
}
You could stay with your direct dependency and then either import a file with the beans defined or import another file where you define the beans as having null values by using a factory bean. See this factory code.
Good luck.
There's no built-in mechanism for this. However, you could write a pretty trivial FactoryBean implementation to do this for you, something like this:
public class OptionalFactoryBean extends AbstractFactoryBean<Object> implements BeanNameAware {
private String beanName;
#Override
public void setBeanName(String beanName) {
this.beanName = BeanFactoryUtils.originalBeanName(beanName);
}
#Override
protected Object createInstance() throws Exception {
if (getBeanFactory().containsBean(beanName)) {
return getBeanFactory().getBean(beanName);
} else {
return null;
}
}
#Override
public Class<?> getObjectType() {
return null;
}
}
You can then use it like this:
<bean id="mainAppBean" class="com.someapp.MyApplication">
<constructor-arg index="0" ref="localBean"/>
<constructor-arg index="1">
<bean name="optionalBeanReference1" class="com.someapp.OptionalBeanFactory"/>
</constructor-arg>
<constructor-arg index="2">
<bean name="optionalBeanReference2" class="com.someapp.OptionalBeanFactory"/>
</constructor-arg>
</bean>
Given that the bean references in your XML config are defined via expression language (EL) you can do the following:
<property name="cache" value="#{getObject('optionalCache')}" />
which makes use of the BeanExpressionContext.getObject() method. See here for more details.
I have three apps in a Spring 2.5 managed project that share some code and differ in details.
Each application has a property (java.lang.String) which is used before the application context is built.
Building the app context takes some time and cannot happen first. As such, it's defined in each individual application. This property is duplicated in the context definition since it is also needed there. Can I get rid of that duplication?
Is it possible to inject that property into my application context?
Have a look at PropertyPlaceholderConfigurer.
The Spring documentation talks about it here.
<bean id="myPropertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:my-property-file.properties"/>
<property name="placeholderPrefix" value="$myPrefix{"/>
</bean>
<bean id="myClassWhichUsesTheProperties" class="com.class.Name">
<property name="propertyName" value="$myPrefix{my.property.from.the.file}"/>
</bean>
You then have reference to that String to anywhere you'd like in your application context, constructor-arg, property etc.
With spring 3.0 you have the #Value("${property}"). It uses the defined PropertyPlaceholderConfigurer beans.
In spring 2.5 you can again use the PropertyPlaceholderConfigurer and then define a bean of type java.lang.String which you can then autowire:
<bean id="yourProperty" class="java.lang.String">
<constructor-arg value="${property}" />
</bean>
#Autowired
#Qualifier("yourProperty")
private String property;
If you don't want to deal with external properties,you could define some common bean
<bean id="parent" class="my.class.Name"/>
then initialize it somehow, and put into common spring xml file, lets say common.xml. After that, you can make this context as a parent for each or your apps - in your child context xml file:
<import resource="common.xml"/>
and then you can inject properties of your parent into the beans you're interested in:
<bean ...
<property name="myProperty" value="#{parent.commonProperty}"/>
...
</bean>