Creating a singleton bean using runtime parameters - java

I am new to the Spring framework and can't find a way to achieve the following:
I am using a class whose attributes are all private and there are no setters (the intended way to use objects of that class is to set attributes once with a constructor) - I will refer to it as Preferences. I also have a few classes that each has the same instance of Preferences as an attribute. Preferences is intended to contain certain properties, among which some can only be resolved at runtime (e.g. provided by the user).
In my .xml file I would write something along the lines of:
<bean id="preferenes" class="Preferences" scope="singleton">
<constructor-arg index="0" value="defaultAttrOne" />
<constructor-arg index="1" value="defaultAttrTwo" />
<constructor-arg index="2" value="defaultAttrThree" />
</bean>
<bean id="someOtherBean" class="SomeOtherClass" scope="singleton">
<constructor-arg index="0" ref="preferences" />
</bean>
That is, I could provide default values and replace some of them with custom ones at runtime. As I cannot modify attributes of an existing instance of Preferences, I would have to construct a new object and somehow make the instance of SomeOtherClass point to that new object (is this possible through the bean mechanism?).
Rather, I'd pass the desired runtime constructor arguments to the preferences bean before instantiating any of the beans (those arguments will be known before the first call to the ApplicationContext's constructor). I know there is a flavour of the getBean() method that takes varargs as initialization parameters, though it only applies to prototype beans. In this case I want to initialize Preferenes once and have all helper classes refer to that single instance.
Thank you for any hints.

This is pretty much what Spring does for you by default so there is nothing special you'll have to do: if you create that singleton bean reference (called preferences), you'll be able to inject it to any other bean as you would expect.
Regarding your attributes with default values, there's several ways to achieve that:
Regular XML config
You can keep a purely XML-based configuration if you want and configure a PropertyPlaceholderConfigurer with default values. Something like:
<bean class="org.s.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="prefrences.properties"/>
</bean>
<bean id="preferenes" class="Preferences" scope="singleton">
<constructor-arg index="0" value="$[preferences.one:12]" />
<constructor-arg index="1" value="$[preferences.two:AUTO]" />
<constructor-arg index="2" value="$[preferences.three:false]" />
</bean>
And have a prefrences.properties at the root of the classpath hold the specific values if you don't want the default
prefrences.three=true
FactoryBean
As you're already using XML, you can go with a FactoryBean that would create the Preferences instance, something like
<bean id="preferences" class="org.myproject.PreferencesFactoryBean"/>
in the code of the factory you could use whatever mechanism you want to retrieve the non default values for your configuration, including injecting custom properties.
Java config
You can also go the java config way but as you're a beginner this may be a bit of a change. However, java config is really powerful and flexible so you may want to give it a try.
#Configuration
#PropertySource("classpath:preferences.properties")
public class AppConfig {
#Value("${preferences.one}")
private int preferenceOne = 12;
#Value("${preferences.two}")
private MyEnum preferenceTwo = MyEnum.AUTO;
#Value("${preferences.three}")
private boolean preferenceThree;
#Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
#Bean
public Preferences preferences() {
return new Preferences(preferenceOne, preferenceTwo, preferenceThree);
}
}

Related

What is the xml equivalent of this bean configuration where an object is being passed for which there is no bean configuration defined?

I need to add OAuth client to a Spring 3 project. I need to use xml based configuration. And I want to know the xml equivalent of the following bean configuration I found in another Spring project. Note that there is an input parameter in the bean definition where an object of type OAuth2ClientContext is being passed (OAuth2ClientContext is an Interface) and is named clientContext. But no bean definition is written anywhere for clientContext. What does this mean? And how would you write this in xml?
#Bean
public OAuth2RestTemplate oauth2RestTemplate(OAuth2ClientContext clientContext){
return new OAuth2RestTemplate(oauth2Resource(), clientContext);
}
The configuration should be like this
<bean id="client" class="package.OAuth2ClientContext" />
<bean id="resource" class="package.Oauth2Resource" />
<bean id="restTemplate" class="package.Oauth2Resource">
<property name="nameOfPropertyResource" ref="resource" />
<property name="nameOfPropertyClient" ref="client" />
</bean>
are you sure that the bean client is not declared? Maybe it’s declared in some jar? If yes you should find it’s name and use the name in the ref

Inject Resolved Properties Object to Another Bean

I'd like to inject a java.util.Properties object into another bean through XML config. I have tried the solution listed here without success, presumably because the bean is being injected before the property resolution occurs. Is there a way that I can force the java.util.Properties object to be resolved before being injected to my class?
Below is the trimmed/edited version of what I have. PropertiesConsumingClass does receive the merged, but unresolved properties of a, b, and c properties files.
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="properties" ref="allProperties" />
</bean>
<bean id="allProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="propertiesArray">
<util:list>
<util:properties location="classpath:a.properties" />
<util:properties location="classpath:b.properties" />
<util:properties location="classpath:c.properties" />
</util:list>
</property>
</bean>
<bean class="PropertiesConsumingClass">
<constructor-arg index="0" ref="allProperties" />
</bean>
Your example doesn't work because what Spring calls a property isn't the same thing as what Java calls a property. Basically, a Spring property lives in a <property> tag, and this is what gets resolved by PropertyPlaceholderConfigurer. You can also use property placeholders inside #Value annotations. Either way you have a string with ${} placeholders that get resolved, possibly the string is converted to the correct type, and injected into your bean.
java.util.Properties are used to resolve placeholders in Spring properties, but they aren't considered for resolution themselves. Any properties in a., b., or c.properties will be substituted into Spring property placeholders, but PropertyPlaceholderConfigurer doesn't know or care if the values it gets from those files have ${} in them.
Now, Spring Boot does resolve placeholders inside its config files, but it has special sauce to accomplish that. It's also a very opinionated library that wants to control your app's lifecycle and does lots of magical things behind the scenes, so it's very hard to adopt or drop except at the very beginning of a project.

How to create java.util.Optional<T> object from Spring bean?

Java
public class MyObject{}
public class MyFactory{
private Optional<MyObject> myproperty;
public Optional<MyObject> getMyproperty{...}
public void setMyproperty{...}
}
Spring config xml (doesn't work)
<bean id="myproperty" class="java.util.Optional">
<constructor-arg>
<value>com.MyObject</value>
</constructor-arg>
</bean>
<bean id="myfactory" class="com.Myfactory">
<property name="myproperty" ref="myproperty" />
</bean>
Does spring support generics beans?
The reason for using Optional is it provide some useful features such as checking value if null. You can complete checking and further action in one line of code.
getMyproperty().ifPresent(id -> call.setId(id));
Seems the problem have nothing to do with generics.
You simply need to properly tell Spring to create the bean using a factory method, as Optional can only be created though factory methods. Something like:
<bean id="myproperty" class="java.util.Optional" factory-method="of">
<constructor-arg type="java.lang.Object" value="com.MyObject" />
</bean>
for which it is supposed to mean creating the myproperty bean by Optional.of(com.MyObject.class) (Change the factory-method to ofNullable if that's the one you want to use)
Another option is to use SpEL (Spring Expression Language):
<bean id="mybean" ...>
<property name="optProp" value="#{ T(java.util.Optional).of( #wrapme) }"/>
</bean>
Where "wrapme" is the name of a bean defined elsewhere that you want to wrap in java.util.Optional.

Reuse same instance of prototype bean twice - Spring

I have a problem with Spring: I need to reuse the same instance of bean twice, but not making it singleton.
Here is a brief ApplicationContext:
<bean class="a.b.c.Provider" id="defaultProvider" scope="prototype">
<constructor-arg ref="lifecycle" />
<constructor-arg ref="propertySetter" />
</bean>
<bean name="lifecycle" class="a.b.c.Lifecycle" scope="prototype">
<constructor-arg ref="someParam" />
... and more args
</bean>
<bean id="propertySetter" class="a.b.c.PropertySetter" scope="prototype">
<constructor-arg ref="lifecycle" />
</bean>
So, I need to have fully initialized Provider with Lifecycle and PropertySetter inside,
and this PropertySetter must contain reference to same Lifecycle, as the Provider have.
When I define lifecycle and propertySetter as singletons, it causes big problems, because
if I create more than one Provider, all instances of Provider class shares same lifecycle
and property setter, and it's breaking application logic.
When I try to define all beans as prototypes, Lifecycles in Provider and in PropertySetter are not the same => exceptions again.
I have one solution: to pass to Provider only Lifecycle and create PropertySetter inside Provider java constructor (by extending Provider).
It is working well, but only in my local environment. In production code I can't extend 3pty Provider class, so I can't use this solution.
Please advise me, what most appropriate to do in this situation?
You don't need to extend Provider. Just create your own ProviderFactory that will take reference to lifecycle and will create PropertySetter and then Provider:
public class ProviderFactory {
public static create(Lifecycle lc) {
return new Provider(lc, new PropertySetter(lc));
}
}
Here is Spring declaration:
<bean id="defaultProvider" scope="prototype"
class="a.b.c.ProviderFactory" factory-method="create">
<constructor-arg ref="lifecycle" />
</bean>

spring - constructor injection and overriding parent definition of nested bean

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;
}
}

Categories