How to create a object that need dynamic parameter - java

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.

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.

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.

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

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.

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.

Maybe you have to change the constructor to:
Class A{
A(Request request){ this.x=calculate(request); ....}
}

Related

What is the best practice: Use prototype bean instead of new () operator

I am trying to understand what would be the correct usage of Spring prototype bean.
May be the following code sample will help in you understanding my dilemma:
List<ClassA> caList = new ArrayList<ClassA>();
for (String name : nameList) {
ClassA ca = new ClassA();
//or Shall I use protypebean, using method lookup I can inject the dependency of ClassA.
// ClassA ca = getPrototypeClassA();
ca.setName(name);
caList.add(ca);
}
So my exact point is in this scenario shall I go with method injection or new() operator.
Provide your view with justification.
You can make use of either of the ways, because ultimately client code is responsible for handling the life-cycle of the prototype bean rather than spring container.
According to Spring-docs,
In some respects, you can think of the Spring containers role when
talking about a prototype-scoped bean as somewhat of a replacement for
the Java 'new' operator. All lifecycle aspects past that point have to
be handled by the client.
Spring does not manage the complete lifecycle of a prototype bean: the
container instantiates, configures, decorates and otherwise assembles
a prototype object, hands it to the client and then has no further
knowledge of that prototype instance. It is the responsibility of the
client code to clean up prototype scoped objects and release any
expensive resources that the prototype bean(s) are holding onto.
If ClassA needs to have #Autowired references, then go for a prototype bean.
Otherwise a simple POJO (that the Spring container is unaware of) will do.
It seems that your instance need some runtime values in order to initialise properly. In such case ,it depends on if you need to use spring feature such as AOP for the ClassA instance. If yes , go with the method injection .If not , you can consider using factory pattern . Much more OO and cleaner to me :
Something like the following . You should get the idea.
#Component
public class FactoryForClassA {
#Autowired
private FooBean someDependencyForClassA;
public ClassA create(String name){
ClassA a = new ClassA(someDependencyForClassA);
a.setName(name);
return a;
}
}
And the client code:
#Autowired
private FactoryForClassA factoryForClassA;
List<ClassA> caList = new ArrayList<ClassA>();
for (String name : nameList) {
ClassA a = factoryForClassA.create(name);
caList.add(ca);
}

Inject properties after object creation

I have a class that has some dynamic attributes which I received on the constructor.
Other properties on this same class are/can be injected by spring.
I want to know if this is possible and how should I config my application. I using spring 3 and xml configuration.
Here is an example:
class MyClass {
private MyClass2 obj2; // should be injected by spring
private Long myId;
public MyClass(Long dynamicId) {
myId = dynamicId;
}
public void doSomehting() {
obj2.doOtherStuff(this);
}
}
So, what I want, since I must create MyClass dynamically, is that after I call new MyClass(1234), the obj2 gets injected by Spring.
Is it possible?
use an ObjectFactory to retrieve the bean from the di-container. If you wrap this factory in a factory object of your own, you can set any property and still have the bean managed by Spring. Since you want the bean to have some dynamically set property think it through whether you need a singleton-scoped bean (default) or a prototype one.
If you intend to do this from xml config you need to muck around with objectfactorycreatingfactorybean. Spring documentation is excellent, just follow the example.
If you do annotation-based configuration, you just need to autowire the ObjectFactory. Note that YourClass has to be declared as a bean too!
I'm pretty sure that's not possible. It looks like you want a (scary music) factory.
class MyClassFactory {
private final MyClass2 object;
public(MyClass2 object) {
this.object = object;
}
public createMyClass(Lond id) {
return new MyClass(id, object);
}
}
If you create an instance of MyClass dynamically with the new operator, that instance is outside of Spring's bean factory, so Spring cannot inject anything. You really have two options, from what I can see.
1) Make MyClass a prototype bean so Spring gives you a new instance every time you need it. You would need to then define obj2 as a property to be set (or Autowired).
2) Inject obj2 via Spring into the class that is creating the instance of MyClass and make obj2 a constructor argument so you have to inject it.
My 0.02 from what I read from your question. A note of caution, when creating a new instance in Java, it is always outside the bean factory and all work performed outside the bean factory looses the Spring proxy behaviors. Be very careful here, you can get yourself into a rabbit hole that can be hard to track down.

Create a bean and autowire it

I currently have numerous classes with a field like
private MyStuff myStuff = new MyStuff();
It would be preferable if there was a MyStuff singleton which all the classes used. Our project has a MyConfiguration class with some Beans in it, but they don't seem to get used, at least not directly, so I can't use them for examples. I have been tasked to create a MyStuff bean in the MyConfiguration class, and then inject it into my other classes.
What I have so far:
#Configuration
public class MyConfiguration
{
#Bean
public MyStuff myStuff()
{
return new MyStuff();
}
}
public SomeClass
{
public void dealWithStuff()
{
someStuff.myMethod();
}
#Autowired
private MyStuff someStuff;
}
This compiles but does not run. someStuff is null when it tries to call myMethod(). Apparently it does not see the bean or make the connection. What am I missing?
I'm going to make an assumption, so correct me if I'm wrong: you are creating instances of SomeClass yourself. Something like
SomeClass someInstance = new SomeClass();
outside of any Spring component.
In this case, how do you expect Spring to inject anything since it's not even process it.
You need to let Spring create objects (beans) that need to have other beans injected.
The problem is naming. Refer to this for a complete description but briefly it says
If you intend to express annotation-driven injection by name, do not primarily use #Autowired, even if is technically capable of referring to a bean name through #Qualifier values. Instead, use the JSR-250 #Resource annotation, which is semantically defined to identify a specific target component by its unique name, with the declared type being irrelevant for the matching process.
It means that you should be doing something like this:
#Resource(name="myStuff")
public void setSomeStuff(MyStuff someStuff){
this.someStuff = someStuff;
}
The reason is that you have defined your bean as myStuff but referring it as someStuff.
Also to have a singleton instance, all you need is to define its scope as singleton in your Spring Configuration as following:
#Configuration
public class MyConfiguration
{
#Bean #Scope(BeanDefinition.SCOPE_SINGLETON)
public MyStuff myStuff()
{
return new MyStuff();
}
}
As I see in your code, your object reference name is "someStuff" but you are referring to myStuff you should use someStuff.myMethod();

How can a Spring bean detect if it itself has been wrapped in an AOP proxy?

We are using Spring's TransactionInterceptor to set some database partition information using ThreadLocal whenever a DAO method marked with the #Transactional annotation is executed. We need this to be able to route our queries to different database partitions.
This works fine for most DAO methods:
// this causes the invoke method to set a thread-local with the host name of
// the database server the partition is on
#Transactional
public int deleteAll() throws LocalDataException {
The problem is when we need to reference the DAO proxy object itself inside of the DAO. Typically we have to have the caller pass in the proxy-dao:
public Pager<Foo, Long> getPager(FooDao proxyDao) {
This looks like the following in code which is obviously gross.
fooDao.getPager(fooDao);
The problem is that when we are inside of FooDao, the this is not the proxy DAO that we need.
Is there a better mechanism for a bean to discover that it has a proxy wrapper around it? I've looked at the Spring AOPUtils but I see no way to find the proxy for an object. I don't want isAopProxy(...) for example. I've also read the Spring AOP docs but I can't see a solution there unless I implement my own AOP native code which I was hoping to avoid.
I suspect that I might be able to inject the DAO into itself with a ApplicationContextAware utility bean and a setProxyDao(...) method, but that seems like a hack as well. Any other ideas how I can detect the proxy so I can make use of it from within the bean itself? Thanks for any help.
A hacky solution along the lines of what you have suggested, considering that AspectJ compile time or load time weaving will not work for you:
Create an interface along these lines:
public interface ProxyAware<T> {
void setProxy(T proxy);
}
Let your Dao's implement the ProxyAware implementation, now create a BeanPostProcessor with an Ordered interface to run last, along these lines:
public class ProxyInjectingBeanPostProcessor implements BeanPostProcessor, Ordered {
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (AopUtils.isAopProxy((bean))){
try {
Object target = ((Advised)bean).getTargetSource().getTarget();
if (target instanceof ProxyAware){
((ProxyAware) target).setProxy(bean);
}
} catch (Exception e) {
// ignore
}
}
return bean;
}
#Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
}
It is ugly, but works.
There is a handy static utility AopContext.currentProxy() method provided by Spring which returns a proxy to object from which it was called.
Although using it is considered a bad practice, semantically the same method exists in Java EE as well: SessionContext.getBusinessObject().
I wrote few articles about this utility method and various pitfalls: 1, 2, 3.
Use Spring to inject a bean reference into the bean, even the same bean, just as you would for any other bean reference. No special action required.
The presence of such a variable explicitly acknowledges in the class design that the class expects to be proxied in some manner. This is not necessarily a bad thing, as aop can change behavior that breaks the class contract.
The bean reference would typically be for an interface, and that interface could even be a different one for the self-referenced internal methods.
Keep it simple. That way lies madness. :-)
More importantly, be sure that the semantics make sense. The need to do this may be a code smell that the class is mixing in multiple responsibilities best decomposed into separate beans.

Spring IoC - Ensuring all beans are created before #PostConstruct/afterProperiesSet

I've got a project using Spring IoC for dependency injection, and I'm trying to slightly simplify my model by having one central location for accessing most of my beans.
I'm running into a problem using the #PostConstruct mechanism, or alternatively when implementing the InitializingBean interface. While all the dependencies in that particular bean may have been resolved, the dependencies in injected beans may not have been. For example I have:
public class A {
public void doSomething() {};
}
public class B {
private A objectA;
#Required
public void setObjectA(A objectA) {
this.objectA = objectA;
}
public A getObjectA() {
return objectA;
}
}
public class C implements InitializingBean {
private B objectB;
#Required
public void setObjectB(B objectB) {
this.objectB = objectB;
}
public void afterPropertiesSet() throws Exception {
objectB.getObjectA().doSomething();
}
}
My context.xml file defines these three beans and injects the appropriate properties, but I get a NullPointerException when the object of class C gets instantiated and the afterPropertiesSet method is called, debugging shows me that the call to getObjectA() returns null. If I inject object A directly into class C I get no errors.
Is there a mechanism I can use to ensure that all beans have been completely instantiated before my afterPropertiesSet method / any method annotated with #PostConstruct is called?
Thanks,
Joseph.
The afterPropertiesSet() is little too early to call methods on injected dependencies. Indeed, the init-method (if you have that in XML) is called after afterPropertiesSet() and then postProcessAfterInitialization() of BeanPostProcessors are called. You have #Required annotation and so, ofcourse, RequiredAnnotationBeanPostProcessor is executed.
Lifecycle callback methods are what they are: they inform you about lifecycle events and their purpose is not to enable you to hijack the task that Spring is performing. (Though you can do it as you did when directly injecting object A in C- but it is not recommended).
If you want to use object A (or any other spring bean for that matter) in class C, then I would recommend to use ApplicationContextAware (or BeanFactoryAware as the case may be) and use getBean() method to get fully baked and ready to serve bean!
Implement ApplicationListener[ContextRefreshedEvent] and do your work in onApplicationEvent(). Word of caution - ContextRefreshedEvent is sometimes published multiple times, so you may want to set a flag after the first time you get it to ignore the additional events.
Use #DependsOn to ensure that A is instantiated before C.

Categories