SpEL: get current bean name during bean instantiation - java

I am attempting to use SpEL to get the name of the bean currently being instantiated to allow multiple beans of same class to be created with different properties supplied by #PropertySource. I am hoping for something like the following:
public class SampleBean {
#Value("${#{CurrentBeanName}.val}")
private String val
}
Other bean:
public class OtherBean {
#Autowired
#Qualifier(name="BeanA")
SampleBean beanA;
#Autowired
#Qualifier(name="BeanB")
SampleBean beanB;
}
properties file:
BeanA.val=VALUE A
BeanB.val=VALUE B
If I add beanName=BeanA to my properties file, I am able to get this to work with
#Value("${${beanName}.val}")
Any ideas on what to do for #{BeanName}? If this is impossible then so be it, but if it works it would be much cleaner than my current solution.
EDIT:
Or any way to pass a constant from the xml bean definition to SpEL? example:
<bean id="BeanA" class="...">
<property name="prefix" value="BeanA"/>
</bean>
java:
public class SampleBean {
#Value("${#{prefix}.val}")
private String val
}
Any sort of attribute or anything would work
EDIT2:
This is trivial in old XML based config
spring.xml:
<bean id="beanA" class="SampleBean">
<property name="val" value="${BeanA.val}"/>
</bean>
<bean id="beanB" class="SampleBean">
<property name="val" value="${BeanB.val}"/>
</bean>
SampleBean.java:
public class SampleBean {
private String val;
public void setVal (String val) {
this.val = val;
}
}
However when switching to the new #Value annotations to get rid of all the setters, it seems non-singletons with diff properties aren't supported (i.e. no way to dynamically filter #Value arguments on bean creation)

No; it is not possible to reference the current bean.
EDIT
To address your comment below, the Java Configuration equivalent of
<bean id="BeanA" class="com.my.Foo">
<property name="prefix" value="BeanA"/>
</bean>
is
#Bean
public Foo BeanA() {
Foo a = new Foo();
a.setPrefix("BeanA");
}
although, by convention, you'd probably name it beanA.

If you have singleton bean types you could just use a static final variable for the name and then reference that. But the bigger issue is that you will be breaking the Spring inversion of control principals if you begin depending on Spring bean names, which is why this sort of thing isn't done. Pretty much want to focus on creating modules and domains for your project. If you begin accessing components coming from the Spring Context directly (such as the bean name) you will find that your modules will become brittle, hard to change and very hard to reason about as they begin to depend on behaviour from seemingly unrelated modules, such as the Spring Dependency Injection Framework. Although you may have a valid use-case for doing this you just need to be very very careful.

Related

how to inject parent class property with spring annotation

parent class is like this:
public class BaseDAO{
private DBRoute defaultDB;
public DBRoute getDefaultDB()
{
return this.defaultDB;
}
public void setDefaultDB(DBRoute defaultDB)
{
this.defaultDB = defaultDB;
}
}
I have create beans like below:
<bean id="adsConfigDB" class="net.flyingfat.common.dbroute.config.DBRoute">
<constructor-arg value="adsConfig" />
</bean>
<bean id="adsBizDateDB" class="net.flyingfat.common.dbroute.config.DBRoute">
<constructor-arg value="adsBizDate" />
</bean>
I want to inject superclass property defaultDB in subclass through byName, not byType, which is in subclass inject defaultDB using adsConfigDB or adsBizDateDB. Is there any way to do this with spring annotations? I already tried Autowired or Resource with constructor which doesn't work. By the way, I already know this can be done using XML.
#Qualifier annotation – This annotation is used to avoid conflicts in bean mapping and we need to provide the bean name that will be used for autowiring. This way we can avoid issues where multiple beans are defined for same type. This annotation usually works with the #Autowired annotation. For constructors with multiple arguments, we can use this annotation with the argument names in the method.
Your code will be like this..
#Autowired
#Qualifier("adsConfig")
private DBRoute defaultDB;

How to autowire a class with non-empty constructor?

I'd like to #Autowired a class that has a non-empty constructor.
Just the the following as an example, it does not necessairly have to be a view/service. Could be whatever component you like, having non-default constructor:
#Component
class MyViewService {
//the "datasource" to show in the view
private List<String> companies companies;
private MyObject obj;
public MyViewService(List<String> companies, MyObject obj) {
this.companies = companies;
this.obj = obj;
}
}
Of course I cannot just write
#Autowired
private MyViewService viewService;
as I'd like to use the constructor with the list. But how?
Are there better approaches than refactoring these sort of constructors to setters? I wouldn't like this approach as ideally the constructor forces other classes to provide all objects that are needed within the service. If I use setters, one could easily forget to set certain objects.
If you want Spring to manage MyViewService you have to tell Spring how to create an instance of it. If you're using XML configuration:
<bean id="myViewService" class="org.membersound.MyViewService">
<constructor-arg index="0" ref="ref_to_list" />
<constructor-arg index="1" ref="ref_to_object" />
</bean>
If you're using Java configuration then you'd call the constructor yourself in your #Beanannotated method.
Check out the Spring docs on this topic. To address a comment you made to another answer, you can create a List bean in XML as shown in the Spring docs. If the list data isn't fixed (which it's probably not) then you want to use an instance factory method to instantiate the bean.
In short, the answers you seek are all in the Spring docs :)
If a component has a non-default constructor then you need to configure the constructor in the bean configuration.
If you are using XML,
it might look like this (example from the spring reference document):
<beans>
<bean id="foo" class="x.y.Foo">
<constructor-arg ref="bar"/>
<constructor-arg ref="baz"/>
</bean>
<bean id="bar" class="x.y.Bar"/>
<bean id="baz" class="x.y.Baz"/>
</beans>
The key here is constructor wiring of the bean that will be used for the #AutoWire.
The way you use the bean has no impact.

How do I update the value of an #Autowired String bean in Spring?

I have a String that I'm autowiring as a bean. The value for the String is set via a properties file, and is loaded at runtime. That much I can verify. Here's my XML:
<context:property-placeholder location="classpath:my-app.properties" />
<bean id="loadedProp" class="java.lang.String">
<constructor-arg>
<value>${loaded-prop}</value>
</constructor-arg>
</bean>
And in my application, I autowire in the bean:
#Component
public class Foo {
#Autowired
private String loadedProp;
}
Everything works dandy. I have multiple components that autowire in this bean. What I'm trying to do is, while the application is running, update the value of the bean to be something else, so that everywhere the bean is autowired in, it uses the most up to date value. Is it possible to do this, or do I just need to restart everytime I want to change the value?
After reading a few of the other answers and comments, I was able to figure out a solution. I ended up creating a simple class:
public class LPropBean {
private String loadedProp;
public LPropBean(String loadedProp) {
this.loadedProp = loadedProp;
}
// getters and setters...
}
I updated my XML file:
<bean id="lPropBean" class="LPropBean">
<constructor-arg>
<value>${loaded-prop}</value>
</constructor-arg>
</bean>
And updated all of the #Components that autowire in the bean:
#Autowire
private LPropBean lPropBean;
// ... later ...
lPropBean.setLoadedProp(newProp);
// ... later ...
lPropBean.getLoadedProp();
I'm sure there is a more elegant way, but this worked exactly how I needed it to.
Since String is immutable, you cannot just change its underlying value and have everyone that has a reference to it be updated.
You can change the reference of the String that an instance of Foo is holding onto to point to a different String, but it will only be realized by objects that are working with the specific Foo you updated. If Foo is a Spring singleton, this shouldn't be an issue though...
Every time you want to change your spring injected values through changing the configuration, you are going to have to restart your container, which usually involves restarting your server.

Spring:autowired field is null

I need to wire external lib class to my bean,in order to use it as singleton.
.xml config:
<bean id="myBean" class="com.my.MyBean">
<property name="someLib" value="com.ExternalBean" />
</bean>
java bean:
#Service
public class MyBean {
#Autowired
private ExternalBean externalBean;
public void setExternalBean(ExternalBean externalBean) {
this.externalBean = externalBean;
}
Further I use wired variable externalBean in public method ,in order not to instantiate it in every method call.
Problem is it null.
Do I wire bean correctly?What is mistake.
You have to define the external class as a bean in order to make #Autowired work.
<bean id="externalBean" class="some.external.package.ExternalBean">
</bean>
<bean id="myBean" class="com.my.MyBean">
</bean>
Also, if you use #Autowired you don't need the setter for it.
loodakrawa is right. A second thing that can cause a problem is, that you have a xml bean declaration for myBean and additional annotated the bean with #Service. I guess this will cause trouble as soon as use enable component scan.
I think that the better ide ais to use context path scan:
<context:component-scan base-package="some.external.package">
</context:component-scan>
Make sure that all these classes are within the package. Then mark both classes with one of the Annotations (#Repository, #Service, #Component).
One of the benefits, no setter required.
P.S: If you re using scan base you don't need to declare class as bean, annotations are enough

Spring prototype beans in combination with singleton beans and dependency injection. Is there an approach that is configuration only?

I have a singleton bean which needs for each call of a function to return a reference to a different (new) prototype bean. The only way that I can think of doing this is to programmatically retrieve a new prototype bean instance from the BeanFactory/ApplicatioContext by invoking its getBean() method. Code sample will follow...
Is there a better way to do this? Only via configuration, hopefully? (Personally, I doubt there is...)
<bean id="protoBean" scope="prototype"
class="com.blahblah.ProtoBean" />
<bean id="singletonBean"
class="com.blahblah.SingletonBean" />
public class ProtoBean {
....
}
public class SingletonBean {
private BeanFactory factory;
public ProtoBean dispense() {
return (ProtoBean) factory.getBean("protoBean");
}
....
}
take a look at Method Injection
From Spring 3.0, we can use <aop:scoped-proxy> for dependency injection of the proper scope. Behind the scene, Spring injects proxied objects and is responsible for finding the right scope context, may it be prototype, session or request etc. See the official documentations here.
And to make life easier, Spring has also introduced proxyMode attribute for #Scope, so we are not limited to XML declarations only. For example:
#Scope(value = "prototype", proxyMode = ScopedProxyMode.INTERFACES)
Make sure to document clearly the injected bean is a proxy to warn others that getClass() and casting may not yield the expected result. Also, make sure equals() and hashCode() in the proxied class use access methods rather than directly accessing class variables.
Using method injection makes the singleton-bean class difficult to unit-test (you need to create a subclass to implement the method which gives out the dependency). Plus it's less reusable because you can't directly instantiate it, so if you're not using Spring and want to use this class, you'll need to subclass and provide the bean-returning method.
A better approach IMHO is to use a proxy, a prototype target source and a prototype target bean, as follows. Such a singleton-bean class is easily unit-testable and better reusable.
<bean id="targetPooledObject" class="pool.PooledObject" scope="prototype">
<constructor-arg value="42" />
</bean>
<bean id="prototypeTargetSource" class="org.springframework.aop.target.PrototypeTargetSource">
<property name="targetBeanName" value="targetPooledObject" />
</bean>
<bean id="pooledObject" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetSource" ref="prototypeTargetSource" />
</bean>
<bean id="poolConsumer" class="pool.PoolConsumer">
<property name="pooledObject" ref="pooledObject" />
</bean>
Now we can inject pooledObject into a singleton bean (poolConsumer as shown above), and for every method call that we make on that singleton bean, (e.g. every time we call poolConsumer.callPooledObjectMethod() which in turn calls pooledObject.foo()) we get a new PooledObject bean.
Following is the corresponding code:
public class PooledObject
{
private int x;
public PooledObject(int x)
{
this.x = x;
}
public void foo()
{
System.out.println("foo called");
}
}
public class PoolConsumer
{
private PooledObject pooledObject;
public PooledObject getPooledObject()
{
return pooledObject;
}
public void setPooledObject(PooledObject pooledObject)
{
this.pooledObject = pooledObject;
}
public void callPooledObjectMethod()
{
pooledObject.foo();
}
}

Categories

Resources