i want pass parameter to #autowired ref like
public CoreDao {
private String taskId;
private final String sql = "select ....."+getTaskId()+".....";
public CoreDao(String taskId){
if(taskId.length != 0){
this.taskId = taskId;
}else{
this.taskId = "0";
}
public getTaskId(){
return this.taskId;
}
}
xml is:
<bean id="coreDao" class="Coredao" scope="prototype">
<constructor-arg type="java.lang.String" value=""/>
</bean>
and the CoreService is
#service
CoreService implement ICoreService{
#Autowired
pirvate CoreDao;
}
and xml is
<bean id="coreService" class="CoreService" scope="prototype">
<property name="coreDao" ref="coreDao"/>
</bean>
and i want use getBean("coreService","123") to get the bean with dynamic reference of coreDao.
However,when i use getBean("coreService","123"),the exception is:
error creating bean with name "coreService" defined in file ....xml,could not resolve matching constructor (hint:specify index/type/name arguments for simple parameter to avoid ambiguities.
how could do that?thanks your help.
getBean(String, Object ...) is applicable to bean's constructors or factory methods.
Your CoreService should have CoreService(String s) constructor in order to use this method.
If you want to create many CoreService instances with different parameters, you can create a factory bean which creates all instances for you and puts them together, like
#Component
public class CoreServiceFactoryBean {
#Autowired ApplicationContext ctx;
public CoreService getBean(String param) {
CoreService coreService = ctx.getBean("coreService");
CoreDao coreDao = ctx.getBean("coreDao", parameter);
coreService.setCoreDao(coreDao);
return coreService;
}
}
This way, the logic of creating bean and using it remains separate. Using factories is pretty common to configure prototype scoped beans.
Related
I am currently using spring. I created a restClient that uses a service based on another module. I am trying to instantiate this restClient but I always receive a null pointer exception. After investigation, it appears that the encapsulated attribute (objects) are not instantiating, their nested encapsulated neither.
This is the member variables, my class, the constructor and a method I am trying to call.
private OAuth2RestTemplate oAuth2RestTemplate;
private ConsumedDestinationModel consumedDestinationModel;
#Autowired
private DestinationService<ConsumedDestinationModel> destinationService ;
public DefaultSacRestClient()
{
consumedDestinationModel = getSacConsumedDestinationModel(getDestinationService().getAllConsumedDestinations());
oAuth2RestTemplate = configureOAuth2Credentials(getConsumedDestinationModel());
}
#Override
public List<Story> fetchStories() {
List<Story> stories = new ArrayList<>();
String endpoint = getConsumedDestinationModel().getUrl() + STORIES_URL;
stories.add(oAuth2RestTemplate.getForObject(endpoint, Story.class));
return stories;
}
in my constructor, both methods getSacConsumedDestinationModel() &
configureOAuth2Credentials() returns an object.
but the method getSacConsumedDestinationModel() uses the destinationService which is not instantiated. I dont understand why the destinationService member variable is not instantiated.
Here is the application context which corresponds only to the module I am working on. This application context is appended to the global application context of the application
<bean id="defaultSacRestClient" class="de.hybris.platform.sacintegrationbackoffice.client.impl.DefaultSacRestClient">
<property name="destinationService" ref="destinationService"/>
</bean>
<bean id="destinationService" class="de.hybris.platform.apiregistryservices.services.impl.DefaultDestinationService">
<property name="destinationDao" ref="destinationDao"/>
</bean>
<bean id="destinationDao" class="de.hybris.platform.apiregistryservices.dao.impl.DefaultDestinationDao">
<property name="flexibleSearchService" ref="defaultFlexibleSearchService"/>
<property name="modelService" ref="defaultModelService"/>
</bean>
Is it a bean configuration problem? Am I missing something? There is definitely something I do wrong.
Two possible problems:
Is the class annotated with #Component or #Service?
Some objects are instantiated with the constructor and some aren't.
Try
#Service
public class DefaultSacRestClient {
private final OAuth2RestTemplate oAuth2RestTemplate;
private final ConsumedDestinationModel consumedDestinationModel;
private final DestinationService<ConsumedDestinationModel> destinationService ;
public DefaultSacRestClient(DestinationService<ConsumedDestinationModel> destinationService) {
this.destinationService = destinationService;
this.consumedDestinationModel = getSacConsumedDestinationModel(destinationService.getAllConsumedDestinations());
this.oAuth2RestTemplate = configureOAuth2Credentials(getConsumedDestinationModel());
}
...
}
I have to create a bean where it needs to be cached based on the dynamic constructor value. Example: I need an OrganizationResource bean where "x" (constructor value) organization will have its own specific instance values and "y" (constructor value) will have different values.
But I don't want to create a new object for every x value, I want it to be cached.
I know there are 2 scopes, singleton and prototype, for dynamic constructor value. I am planning to use prototype, but it seems it will create a new object every time, how can I implement cache based on constructor value in spring?
FactoryBean is a way to go. It is very simple, give it a try. All you have to do is create a class implementing FactoryBean and reference it in bean definition file:
package some.package;
import org.springframework.beans.factory.FactoryBean;
public class ExampleFactory implements FactoryBean {
private String type;
public Object getObject() throws Exception {
//Logic to return beans based on 'type'
}
public Class getObjectType() {
return YourBaseType.class;
}
public boolean isSingleton() {
//set false to make sure Spring will not cache instances for you.
return false;
}
public void setType(final String type) {
this.type = type;
}}
Now, in your bean definition file, put:
<bean id="cached1" class="some.package.ExampleFactory">
<property name="type" value="X" />
</bean>
<bean id="cached2" class="some.package.ExampleFactory">
<property name="type" value="Y" />
</bean>
It will make objects based on strategy you implemented in ExampleFactory.getObject().
How to conditionally initialization a class via spring?
If some condtion is true then i want one argument to be passed else some other
argument
<bean id="myFactory" class="Factory">
if something then
<constructor-arg>
<util:map>
<!-- configure your map here, or reference it as a separate bean -->
<entry key="java.lang.String" value="key">....</entry>
</util:map>
</constructor-arg>
else
<constructor-arg>
<util:map>
<!-- configure your map here, or reference it as a separate bean -->
<entry key="java.lang.String" value="key">....</entry>
</util:map>
</constructor-arg>
</bean>
How?
Spring Expression Language might do the trick for you. link
You can do it exactly the way that you have specified. Define a FactoryBean this way, say for eg. For generating a Customer Bean:
public class CustomFactoryBean implements FactoryBean<Customer>{
private int customProperty;
public int getCustomProperty() {
return customProperty;
}
public void setCustomProperty(int customProperty) {
this.customProperty = customProperty;
}
#Override
public Customer getObject() throws Exception {
if (customProperty==1)
return new Customer("1", "One");
return new Customer("999", "Generic");
}
#Override
public Class<?> getObjectType() {
return Customer.class;
}
#Override
public boolean isSingleton() {
return true;
}
}
That is basically it, now based on how you inject in th properties of the factory bean, the actual bean instantiation can be controlled in the getObject method above
I need to create an Object which is in-complete without the constructor argument. Something like this
Class A {
private final int timeOut
public A(int timeout)
{
this.timeOut = timeout;
}
//...
}
I would like this Bean to be spring managed, so that I can use Spring AOP later.
<bean id="myBean" class="A" singleton="false">
</bean>
However my bean needs timeout to be passed as a dynamic value - is there a way to create a spring managed bean with dynamic value being injedcted in the constructor?
BeanFactory has a getBean(String name, Object... args) method which, according to the javadoc, allows you to specify constructor arguments which are used to override the bean definition's own arguments. So you could put a default value in the beans file, and then specify the "real" runtime values when required, e.g.
<bean id="myBean" class="A" scope="prototype">
<constructor-arg value="0"/> <!-- dummy value -->
</bean>
and then:
getBean("myBean", myTimeoutValue);
I haven't tried this myself, but it should work.
P.S. scope="prototype" is now preferable to singleton="false", which is deprecated syntax - it's more explicit, but does the same thing.
Two options spring (no pun intended) to mind:
1. create a timeout factory, and use that as the constructor parameter.
You can create a bean which implements FactoryBean, and it's job is to create other beans. So if you had something that generates salt's for encryption, you could have it return from getObject() a EncryptionSalt object. In your case you're wanting to generate Integers.
Here is an example: http://www.java2s.com/Code/Java/Spring/SpringFactoryBeanDemo.htm
2. create a timeout bean that wraps an int that's dynamically set, and leave that in the "prototype" state so it's created each time
Instead of going to the hassle of creating a factory, the EncryptionSalt object could just be declared as a prototype bean, so when it's injected a new object is created each time. Place the logic into the constructor or somewhere else.
It somewhat depends what value you want the timeout to actually be.
Do it explicitly:
interface Bean {
void setTimeout(int timeout);
}
class BeanImpl implements Bean {
private int timeout;
#Override
public void setTimeout(int timeout) {
this.timeout = timeout;
}
...
}
<bean id="bean" class="BeanImpl" scope="prototype">
...
<!-- Nothing about timeout here -->
...
</bean>
class Client {
private Bean bean;
public void setBean(Bean bean) {
this.bean = bean;
}
...
public void methodThatUsesBean() {
int timeout = calculateTimeout();
bean.setTimeout(timeout);
...
}
}
Given a set of classes wired together by spring. There are several classes that are used with different configuration in multiple instances in the environment. They have different beanid of course.
The problems:
When they make log entries, we dont know exactly which bean made the log, since the log4j displays the classname only
I know that I could use logger instantiated by spring InitializationBean+BeanNameAware interface methods, but I do not want to do it, since I do not want to implement them in all classes
The solution could be:
Having some effect on bean factory to store the id of the beans in a map with the bean reference (key is the ref, name is the value)
Creating an aspect to be applied on every method, that would set an "BeanName" MDC entry in Log4j before the call, and would restore it to the previous value after the call. Meanwhile the previous beannames could be stored in a threadlocal in a stack.
The questions:
How can I change/configure the bean factory to do this trick for me? Is there any customization point I could use to this aim?
How can I avoid memory leaks in the map in the beanid registry? Maybe the registry is not needed at all, if somehow spring can look up the id for a reference.
Do you have any better idea, that would not result in changing ten thousand classes?
Thanks in advance.
UPDATE:
- Does anyone have solution for the prototype beans?
I have managed to hack something together based on this Spring AOP Example.
I am not yet up to speed with Spring 3 so I have implemented this using Spring 2.5 - I dare say there are more elegant ways of achieving what you want. I have implemented this using System.out's for simplicity but these could easily be converted to log4j calls.
Initially I create a map between the Spring's bean names and the string representation of the object (InitBean). This map is used inside the MethodInterceptor - I did try making the MethodInterceptor an InitializingBean but the MethodInterceptor stopped working for some reason.
Performing an equals between the bean passed in via the MethodInterceptor and the other beans in the application context did not work. e.g. by using something like "ctx.getBeansOfType(GoBean.class)" inside the MethodInterceptor. I presume this is because the object passed in via the MethodInvocation was a GoBean whereas objects obtained from the application context at this point are proxied (e.g. something like example.GoBean$$EnhancerByCGLIB$$bd27d40e).
This is why I had to resort to a comparison of object string representations (which is not ideal). Also I specifically do not want to activate the MethodInterceptor logic when calling the "toString" method on an object (as since I'm using toString elsewhere leads to infinite loops and StackOverflow).
I hope this is useful,
applicationContext.xml
<beans>
<bean name="initBean" class="example.InitBean"/>
<bean name="methodLoggingInterceptor" class="example.MethodLoggingInterceptor">
<property name="initBean" ref="initBean"/>
</bean>
<bean name="proxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>go*</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>methodLoggingInterceptor</value>
</list>
</property>
</bean>
<bean name="goBean1" class="example.GoBean" />
<bean name="goBean2" class="example.GoBean" />
<bean name="goBean3" class="example.GoBean" />
</beans>
GoBean.java
public class GoBean {
public void execute(){
System.out.println(new Date());
}
}
SimpleTestClass.java
public static void main( String[] args ){
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
ArrayList<GoBean> goBeans = new ArrayList<GoBean>();
goBeans.add((GoBean) ctx.getBean("goBean1"));
goBeans.add((GoBean) ctx.getBean("goBean2"));
goBeans.add((GoBean) ctx.getBean("goBean3"));
for(GoBean g: goBeans){
g.execute();
}
}
InitBean.java
public class InitBean implements ApplicationContextAware, InitializingBean {
private ApplicationContext ctx;
private Map<String, String> beanMap = new HashMap<String,String>();
public void setApplicationContext(ApplicationContext ac) throws BeansException {
ctx = ac;
}
public void afterPropertiesSet() throws Exception {
for(String beanName: ctx.getBeanNamesForType(GoBean.class)){
beanMap.put(ctx.getBean(beanName).toString(), beanName);
}
}
public Map<String,String> getBeanMap(){
return beanMap;
}
}
MethodLoggingInterceptor.java
public class MethodLoggingInterceptor implements MethodInterceptor{
private InitBean initBean;
public Object invoke(MethodInvocation method) throws Throwable {
if (!"toString".equals(method.getMethod().getName())) {
StringBuilder sb = new StringBuilder();
Object obj = method.getThis();
if (obj instanceof GoBean) {
Map<String,String> beanMap = initBean.getBeanMap();
String objToString = obj.toString();
if (beanMap.containsKey(objToString)) {
System.out.println(beanMap.get(objToString));
sb.append("bean: ");
sb.append(beanMap.get(objToString));
sb.append(" : ");
}
}
sb.append(method.getMethod().getDeclaringClass());
sb.append('.');
sb.append(method.getMethod().getName());
System.out.println(sb.toString() + " starts");
Object result = method.proceed();
System.out.println(sb.toString() + " finished");
return result;
} else {
return method.proceed();
}
}
public void setInitBean(InitBean ib) {
this.initBean = ib;
}
}