4

I always have a question from the 1st day when I used spring. If a class has a constructor that needs two parameters, but these 2 parameters are not fixed, they are generated according to input request, every time they are different, but I need spring container to manage the class's instance, how to achieve this in spring? For example

    Class A{
     A(int x,int y){//omit}
}

but x, and y are not fixed,we need to calculate x and y by our program, then we can create instance for A, in ordinary java code,like below

    int x=calculate(request);
    int y=calculate(request);
    A a=new A(x,y);

But how to make spring manages the class A's instance creation?

Additional information: Why I need Class A is managed by spring, because A depends on some other classes which are managed by spring.

Neo
  • 123
  • 1
  • 9
  • 3
    Why do you want spring to manage these instances? Do you have any members in A that are managed by spring-container? – Vikdor Sep 10 '12 at 15:41
  • yes, I forgot to point out that Class A depends on some other Classes which are managed by spring container. – Neo Sep 11 '12 at 03:40

6 Answers6

7
  • The most straightforward way to do it is to use ApplicationContext.getBean(String name, Object... args) - it can create a prototype-scoped bean passing the given arguments to its constructor. Obviosly it's not a good idea to use ApplicationContext directly in any bean that uses A.

  • A more elegant approach is to hide the creation of A behind a factory. That factory can use the previous approach internally, or it can obtain an instance of a bean in a regular way (Provider<A>, etc) and then call a non-public initialization method to pass that parameters (instead of passing parameters through using constructor).

  • Yet another apporach is to use @Configurable and load-time weaving that allows Spring to initialize objects created with new. Though it requires some extra configuration of runtime environment.

alexbt
  • 16,415
  • 6
  • 78
  • 87
axtavt
  • 239,438
  • 41
  • 511
  • 482
2

they are generated according to input request, every time they are different, but I need spring container to manage the class's instance, how to achieve this in spring?

You don't. Classes that you need to instantiate in response to user input are not meant to be managed by Spring.

Just because you are using Spring to manage some beans, does not mean that all beans/classes should be managed by Spring.

matt b
  • 138,234
  • 66
  • 282
  • 345
  • 1
    Disagree. The poster is asking how to use Spring, not if he should use Spring. Per-user-request beans are supported by Spring's `scope="request"` attribute. – noahlz Sep 10 '12 at 17:53
  • @noahz is correct,I need all beans are managed by spring, because there are dependencies need to be managed by spring, and I think if we are using spring, but still use new , I don't think it's good idea – Neo Sep 11 '12 at 03:36
  • 1
    I think that first point is fair but the second statement "if we are using spring, but still use new , I don't think it's good idea" seems like a dangerous idea. – matt b Sep 11 '12 at 12:37
1

You want your Spring Bean to be defined as a prototype instead of a singleton. That way, on every new request your Spring context will create a new instance of the bean.

In Java config, it will look something like this:

@Scope("prototype") @Bean public MyBean myBean() { ... }

In xml:

<bean id="myBean" class="whatever.MyBean" scope="prototype"> ...

There are also scopes that can be tied to HTTP sessions. See:

http://static.springsource.org/spring/docs/3.0.0.M3/reference/html/ch04s04.html

And, as others pointed out, you will have to define a factory method for your bean:

See: Spring and passing parameters to factory-method in runtime

Community
  • 1
  • 1
noahlz
  • 10,202
  • 7
  • 56
  • 75
0

Maybe you have to change the constructor to:

Class A{
 A(Request request){ this.x=calculate(request); ....}
}
BenMorel
  • 34,448
  • 50
  • 182
  • 322
0

I'd assume that int is replaceable by some Object instance.One way to achieve this is to use Spring's FactoryBean feature to customize the initialization of your bean:

class AFactory implements o.s.b.f.FactoryBean {

  private SomeObject firstParam;
  private OtherObject secondParam;

  public Object getObject() {
    return new A(firstParam, secondParam);
  }

  public Class getObjectType() {
    return A.class;
  }

  public boolean isSingleton() {
    return false; 
    // i.e. every time #getObject() is called a new instance is created === prototype scope
  }

  public void setFirstParam(SomeObject firstParam){}
  public void setSecondParam(OtherObject secondParam){}

}

Note that if SomeObject and OtherObject can be actually other FactorBeans that are factories for the dependencies of A, then every time there is a call to AFactory#getObject(), you'd actually receive a new instance of A that uses fresh instances of its required dependencies.

nobeh
  • 9,784
  • 10
  • 49
  • 66
0

You could try to use this method in BeanFactory class (extended by ApplicationContext)

Object getBean(String name, Object... args)throws BeansException;

in your case: context.getBean("A", x, y);

where "A" is the bean name for class A.