lets say, I have a lot of stuff within my spring application context which looks like that
<bean name="foo.0001" class="com.example.MyClass">
<property name="name" value="foo.name.0001"/>
<property name="zap">
<bean class="com.example.Other">
<property name="name" value="foo.name.0001"/>
</bean>
</property>
<property name="bar">
<bean class="com.example.NextOther">
<property name="name" value="foo.name.0001"/>
</bean>
</property>
</bean>
so the string foo.name.0001 appears within the bean definition several times. Because it is a larger system with several blocks of this configuration, it is quite annoying to modify each of those ids. Ideally I would want to set it only once within a block. Is there a possibility to set some kind of property which exists only in a local scope of a bean definition?
I'm not sure how that would logically work, as you would still have to reference that value somehow to pass it to the nested beans. If you are worried about defining it multiple times, you can have a look at Springs PropertyPlaceholderConfigurer. It will allow you to the following:
<property name="bar">
<bean class="com.example.NextOther">
<property name="name" value="${foo.name.001}"/>
</bean>
</property>
This would allow you to define it once, and reference it from multiple locations.
It depends how much effort you want to put into to this but your requirements could be fufilled by a spring custom namespace. These are ideal when you have lots of identical blocks of beans each configured differently.
Basically you'd define the xml schema then write a bean definition parser that sets up the beans as required.
See here for more details:
http://www.javaworld.com/javaworld/jw-02-2008/jw-02-springcomponents.html
This is how Spring security simplified its xml configuration.
Related
I have 3 projects:
framework
product-a
product-b
Each of the products depends on the framework, but they don't know each other.
I have 3 spring configuration files: one for each project. The configuration file of each product includes (with <import resource="classpath:/...) the configuration file of the framework.
In the framework there is a bean called "manager", which has a property List<AnInterface> theList. The "manager" has a addXxx(anImplementation), which adds elements to the list).
The framework, and each of the product provide implementations of AnInterface, which have to be added to theList.
So in the end, when product-a is running, the manager contains implementations from the framework, and from product-a, idem for product-b
What is the best practice to perform this initialization with Spring ?
The only solution I could think about is to create a dedicated class which contructor will take the manager and a list of contributions, and add them to the manager, but it's ugly because 1/ It manipulate external objects in the constructor, 2/ I have to create a dummy class just to initialize other classes... I don't like that.
I think that code should not know about Spring if it is not really needed. Therefore I would do all initialization in Spring config.
We can use bean definition inheritance and property overriding to do it.
Framework class
public class Manager {
private List<AnInterface> theList;
public void init() {
// here we use list initialized by product
}
}
Framework context
<bean id="manager"
init-method="init"
abstract="true"
class="Manager">
<property name="theList">
<list/> <!-- this will be overriden or extnded -->
</property>
</bean>
Product A context
<bean id="managerA"
parent="manager"
scope="singleton"
lazy-init="false">
<property name="theList">
<list>
<ref bean="impl1"/>
<ref bean="impl2"/>
</list>
</property>
</bean>
Watch out for parent and child properties in such configuration. Not all are inherited from parent. Spring documentation specifies:
The remaining settings are always taken from the child definition: depends on, autowire mode, dependency check, singleton, scope, lazy init.
Moreover, there is also collection merging in Spring so by specifing in child bean
<list merge="true">
you can merge parent and child lists.
I have observed this pattern in a number of projects and some extendable Web frameworks based on Spring.
I have accepted the answer of Grzegorz because it's a clean solution to my initial problem, but here as an alternate answer, the a technical solution to contribute to a list property of an existing bean.
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="manager"/>
<property name="targetMethod"><value>addXxx</value></property>
<property name="arguments"><list value-type="com.xxx.AnInterface">
<value ref="impl1" />
<value ref="impl2" />
...
</list></property>
</bean>
I have the following definition:
<bean id="logger" factory-method="createLog" scope="prototype" class="com.test.beans.LogBean" ></bean>
<bean id="aone" class="com.test.beans.AggregationOne">
<property name="log" ref="logger"></property>
</bean>
<bean id="atwo" class="com.test.beans.AggregationTwo">
<property name="log" ref="logger"></property>
</bean>
Is it possible to recognize for which object (aone or atwo) bean 'logger' is being created?
Why I'm asking: in a legacy application I have one log instance for all classes. I want to change level for some packages, but can't do that (except using filters, what I don't want). For that purpose I want to utilize some spring magic, if it exists for that case )
I don't think it can be done this way. What you could try is a BeanPostProcessor implementation which detects common logger object in beans and replaces it with a specific one.
In my spring batch project I can do something like this:
<bean id="exampleTasklet" class="my.custom.Tasklet">
<property name="message" value="job parameter value: #{jobParameters['arg1']}"/>
</bean>
and the message property will have a value taken from the spring batch job parameters. However, the value that I actually want to assign is very large and I don't want to put it in the xml file. I know this syntax doesn't work, but I would like to do something like:
<bean id="exampleTasklet" class="my.custom.Tasklet">
<property name="message" read-value-from-file="/path/to/file.txt"/>
</bean>
and that file would contain the line "job parameter value: #{jobParameters['arg1']}" which spring will parse as if the file content was in a value="" attribute.
Is there a nice way to do this?
I think what you are looking for is a PropertyPlaceholderConfigurer.
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="/path/to/file.properties" />
<property name="placeholderPrefix" value="#{" />
<property name="placeholderSuffix" value="}" />
</bean>
This is run by Spring as a bean processor and will attempt to resolve placeholder tokens. There is a default instance that will resolve against system properties, using this notation: ${propertyname}. For your notation, you would need to specify the placeholderPrefix/Suffix. When there are multiple bean processors, the order is determined by the order property. By default, if a processor fails to resolve a placeholder, execution fails, but this can be altered by setting ignoreUnresolvablePlaceholders. Since the mechanism is property driven, you probably want to consider a notation like:
<property name="message" value="job parameter value: #{jobParameters.arg1}"/>
Or, if what you're trying to convey is that arg1 is also a parameter, you might try:
<property name="message" value="job parameter value: #{jobParameters.${arg1}}"/>
Spring loops over the bean processors until no replacements are performed, or an exception is raised. So defining a property as ${something.${orOther}} is valid.
I would suggest you to use a String as file name and in your bean open that file.
I'm not sure if I get your problem right. I'm just suggesting something like Spring MessageBundle
Something like this:
<bean id="exampleTasklet" class="my.custom.Tasklet">
<property name="messagePath" location="/path/to/file.txt"/>
</bean>
And in your exampleTasklet read the file and do your thing (I'm not sure what it is)
If anybody came here to do something like this from a properties-file:
If you want a property from a .properties-file to appear in the JobParameters, you won't find ready-to-use solution. You can do the following:
Wrap a bean around your properties file.
Pass this bean to another one which has access to the JobParameters and can pump the properties from the file into that class.
Then you should be able to access your properties with Spring's Expression Language and do something like:
<bean id="myBean" class="my.custom.Bean">
<property name="prop" value="#{jobParameters['arg1']}"/>
</bean>
Alternatively, I think the solution proposed by Devon_C_Miller is much easier. You don't have the properties in your JobParameters then. But if the replacement in the XML configuration is the only thing you want, you only have to change your placeholders to:
${myPropFromFile}
Happy batching, everyone ;-)
I've read the Spring 3 reference on inheriting bean definitions, but I'm confused about what is possible and not possible.
For example, a bean that takes a collaborator bean, configured with the value 12
<bean name="beanService12" class="SomeSevice">
<constructor-arg index="0" ref="serviceCollaborator1"/>
</bean>
<bean name="serviceCollaborator1" class="SomeCollaborator">
<constructor-arg index="0" value="12"/>
<!-- more cargs, more beans, more flavor -->
</bean>
I'd then like to be able to create similar beans, with slightly different configured collaborators. Can I do something like
<bean name="beanService13" parent="beanService12">
<constructor-arg index="0">
<bean>
<constructor-arg index="0" value="13"/>
</bean>
</constructor>
</bean>
I'm not sure this is possible and, if it were, it feels a bit clunky. Is there a nicer way to override small parts of a large nested bean definition? It seems the child bean has to know quite a lot about the parent, e.g. constructor index.
This is a toy example - in practice the service is a large bean definition relying on many other collaborator beans, which have also other bean dependencies. For example, a chain of handlers were created with each bean referencing the next in the chain, which references the next. I want to create an almost identical chain with some small changes to handlers in the middle, how do I it?
I'd prefer not to change the structure - the service beans use collaborators to perform their function, but I can add properties and use property injection if that helps.
This is a repeated pattern, would creating a custom schema help?
Thanks for any advice!
EDIT: The nub of my question is, if I have a really large bean definition, with a complex hiearchy of beans being created (bean having properites that are bean etc.), and I want to create a bean that is almost the same with a few changes, how to I do it? Please mention if your solution has to use properites, or if constructor injection can be used.
Nested vs. top-level beans are not the issue (in fact, I think all the beans are top level in practice.)
EDIT2: Thank you for your answers so far. A FactoryBean might be the answer, since that will reduce the complexity of the spring context, and allow me to specify just the differences as parameters to the factory. But, pushing a chunk of context back into code doesn't feel right. I've heard that spring can be used with scripts, e.g. groovy - does that provide an alternative? Could the factory be created in groovy?
I'm not entirely sure what you are trying to achieve. I don't think you can achieve exactly what you want without creating your own custom schema (which is non-trivial for nested structures), but the following example is probably pretty close without doing that.
First, define an abstract bean to use as a template for your outer bean (my example uses a Car as the outer bean and an Engine as the inner bean), giving it default values that all other beans can inherit:
<bean id="defaultCar" class="Car" abstract="true">
<property name="make" value="Honda"/>
<property name="model" value="Civic"/>
<property name="color" value="Green"/>
<property name="numberOfWheels" value="4"/>
<property name="engine" ref="defaultEngine"/>
</bean>
Since all Honda Civics have the same engine (in my world, where I know nothing about cars), I give it a default nested engine bean. Unfortunately, a bean cannot reference an abstract bean, so the default engine cannot be abstract. I've defined a concrete bean for the engine, but mark it as lazy-init so it will not actually be instantiated unless another bean uses it:
<bean id="defaultEngine" class="Engine" lazy-init="true">
<property name="numberOfCylinders" value="4"/>
<property name="volume" value="400"/>
<property name="weight" value="475"/>
</bean>
Now I can define my specific car, taking all the default values by referencing the bean where they are defined via parent:
<bean id="myCar" parent="defaultCar"/>
My wife has a car just like mine, except its a different model (again, I know nothing about cars - let's assume the engines are the same even though in real life they probably are not). Instead of redefining a bunch of beans/properties, I just extend the default car definition again, but override one of its properties:
<bean id="myWifesCar" parent="defaultCar">
<property name="model" value="Odyssey"/>
</bean>
My sister has the same car as my wife (really), but it has a different color. I can extend a concrete bean and override one or more properties on it:
<bean id="mySistersCar" parent="myWifesCar">
<property name="color" value="Silver"/>
</bean>
If I liked racing minivans, I might consider getting one with a bigger engine. Here I extend a minivan bean, overriding its default engine with a new engine. This new engine extends the default engine, overriding a few properties:
<bean id="supedUpMiniVan" parent="myWifesCar">
<property name="engine">
<bean parent="defaultEngine">
<property name="volume" value="600"/>
<property name="weight" value="750"/>
</bean>
</property>
</bean>
You can also do this more concisely by using nested properties:
<bean id="supedUpMiniVan" parent="myWifesCar">
<property name="engine.volume" value="600"/>
<property name="engine.weight" value="750"/>
</bean>
This will use the "defaultEngine". However, if you were to create two cars this way, each with different property values, the behavior will not be correct. This is because the two cars would be sharing the same engine instance, with the second car overriding the property settings set on the first car. This can be remedied by marking the defaultEngine as a "prototype", which instantiates a new one each time it is referenced:
<bean id="defaultEngine" class="Engine" scope="prototype">
<property name="numberOfCylinders" value="4"/>
<property name="volume" value="400"/>
<property name="weight" value="475"/>
</bean>
I think this example gives the basic idea. If your data structure is complex, you might define multiple abstract beans, or create several different abstract hierarchies - especially if your bean hierarchy is deeper than two beans.
Side note: my example uses properties, which I believe are much clearer to understand, both in Spring xml and in Java code. However, the exact same technique works for constructors, factory methods, etc.
Your example will not work as specified, because the nested bean definition has no class or parent specified. You'd need to add more information, like this:
<bean name="beanService13" parent="beanService12">
<constructor-arg index="0">
<bean parent="beanBaseNested">
<constructor-arg index="0" value="13"/>
</bean>
</constructor>
Although I'm not sure if it's valid to refer to nested beans by name like that.
Nested bean definitions should be treated with caution; they can quickly escalate into unreadability. Consider defining the inner beans as top-level beans instead, which would make the outer bean definitions easier to read.
As for the child beans needing to know the constructor index of the parent bean, that's a more basic problem with Java constructor injection, in that Java constructor arguments cannot be referred to by name, only index. Setter injection is almost always more readable, at the cost of losing the finality of constructor injection.
A custom schema is always an option, as you mentioned, although it's a bit of a pain to set up. If you find yourself using this pattern a lot, it might be worth the effort.
Have you thought of using a factory instead?
You can config beans to have a factory and you could encode the varying parameters in the factory creation...
To expand on the factory pattern from Patrick: you can use a prototype bean to get pre-wired dependencies:
<bean id="protoBean" scope="prototype">
<property name="dependency1" ref="some bean" />
<property name="dependency2" ref="some other bean" />
...
</bean>
Now, this works best if you use setter injection (rather than constructor arguments), i'm not sure you can even do it you require constructor args.
public class PrototypeConsumingBean implements ApplicationContextAware {
public void dynmicallyCreateService(String serviceParam) {
// creates a new instance because scope="prototype"
MyService newServiceInstance = (MyService)springContext.getBean("protoBean");
newServiceInstance.setParam(serviceParam);
newServiceInstance.mySetup();
myServices.add(newServiceInstance);
}
public void setApplicationContext(ApplicationContext ctx) {
m_springContext = ctx;
}
}
I need to load a specific applicationContext.xml file according to a given system property. This itself loads a file with the actual configuration. Therefore I need two PropertyPlaceHolderConfigurer, one which resolves the system param, and the other one within the actual configuration.
Any ideas how to do this?
Yes you can do more than one. Be sure to set ignoreUnresolvablePlaceholders so that the first will ignore any placeholders that it can't resolve.
<bean id="ppConfig1" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreUnresolvablePlaceholders" value="true"/>
<property name="locations">
<list>
<value>classpath*:/my.properties</value>
</list>
</property>
</bean>
<bean id="ppConfig2" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreUnresolvablePlaceholders" value="false"/>
<property name="locations">
<list>
<value>classpath*:/myOther.properties</value>
</list>
</property>
</bean>
Depending on your application, you should investigate systemPropertiesMode, it allows you to load properties from a file, but allow the system properties to override values in the property file if set.
Another solution is to use placeholderPrefix property of PropertyPlaceholderConfigurer. You specify it for the second (third, fourth...) configurer, and then prefix all your corresponding placeholders, thus there will be no conflict.
<bean id="mySecondConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:location="classpath:/myprops.properties"
p:placeholderPrefix="myprefix-"/>
<bean class="com.mycompany.MyClass" p:myprop="${myprefix-value.from.myprops}"/>
Beware -- there might be a bug related to multiple configurers. See http://jira.spring.io/browse/SPR-5719 for more details.
I'm unable to get multiple to work locally... but I'm not yet blaming anyone but myself.
On my own side, playing with PropertyPlaceholderConfigurer both properties :
order (should be lower for first accessed/parsed PPC)
ignoreUnresolvablePlaceholders ("false" for first accessed/parsed PPC, "true" for next one)
and also give 2 distinct id(s) to both PPC (to avoid one to be overwritten by the other)
works perfectly
Hope it helps
You can't do this directly, and this JIRA issue from Spring explains why (check the comment from Chris Beams for a detailed explanation):
https://jira.springsource.org/browse/SPR-6428
However, he does provide a workaround using Spring 3.1 or later, which is to use the PropertySourcesPlaceholderConfigurer class instead of PropertyPlaceholderConfigurer class.
You can download a Maven-based project that demonstrates the problem and the solution from the Spring framework issues github:
https://github.com/SpringSource/spring-framework-issues
Look for the issue number, SPR-6428, in the downloaded projects.
We have the following approach working:
<util:properties id="defaultProperties">
<prop key="stand.name">DEV</prop>
<prop key="host">localhost</prop>
</util:properties>
<context:property-placeholder
location="file:${app.properties.path:app.properties}"
properties-ref="defaultProperties"/>
System property app.properties.path can be used to override path to config file.
And application bundles some default values for placeholders that cannot be defined with defaults in common modules.
Just giving 2 distinct ids worked for me. I am using spring 3.0.4.
Hope that helps.
In case, you need to define two PPC's (like in my situation) and use them independently. By setting property placeholderPrefix, you can retrieve values from desired PPC. This will be handy when both set of PPC's properties has same keys, and if you don't use this the property of ppc2 will override ppc1.
Defining your xml:
<bean name="ppc1"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="properties" ref="ref to your props1" />
<property name="placeholderPrefix" value="$prefix1-{" />
</bean>
<bean name="ppc2"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="properties" ref="ref to your props2" />
<property name="placeholderPrefix" value="$prefix2-{" />
</bean>
Retrieving during Run time:
#Value(value = "$prefix1-{name}")
private String myPropValue1;
#Value(value = "$prefix2-{name}")
private String myPropValue2;