I need to fetch a singleton bean from same ApplicationContext twice in 2 different classes.
Example snippet :
CLass A {
public void foo(){
ApplicationContext context = new ClassPathXmlApplicationContext("common.spring.xml");
MyParametrizedSingletonClass myParametrizedSingletonClass = (MyParametrizedSingletonClass) context.getBean("myParametrizedSingletonClass");
// do more stuff..
}
CLass B {
public void bar(){
ApplicationContext context = new ClassPathXmlApplicationContext("common.spring.xml");
MyParametrizedSingletonClass myParametrizedSingletonClass = (MyParametrizedSingletonClass) context.getBean("myParametrizedSingletonClass");
// do more stuff..
}
Since MyParametrizedSingletonClass is a singletom it if its constructor is called more than once for same constructor arguments it throws error.
How do I cache and reuse ApplicationContext with spring?
You are creating two different context, so even if bean is singleton it will create single instance per context,
if you want to cache application context you can create a class and provide singleton instance of application context
Autowire the bean.
By default the spring injects the autowired beans into required classes and these beans are not created an new everytime. They are singleton by default.
in common.spring.xml file for the bean name myParametrizedSingletonClass add the scope singleton to it as a parameter while defining the bean in the xml file
Related
I am using spring.factories to set bootstrap context
org.springframework.cloud.bootstrap.BootstrapConfiguration=sompePackage.MyBootstrapConfiguration
I was following what is mentioned in this link
https://cloud.spring.io/spring-cloud-commons/multi/multi__spring_cloud_context_application_context_services.html
I noticed 2 things hope you please can help me with
1- I cannot spy on any bean that is created through the bootstrap context, in other words, if I create a bean of type x in MyBootstrapConfiguration, spying on that bean with #SpyBean is not working, I can spy on all other beans but the bootstrap context ones (I am using springboottest)
2- If I inject ApplicationContext somewhere and print all the defined beans, i cannot see the beans that were created in the bootstrap context, in other words, the bean x that is created in MyBootstrapConfig is not there. However, #Autowired is working fine and the bean is injected correctly.
My questions are:
1- How can i spy or mock the bootstrap context beans?
2- If i cannot find these beans in ApplicationContext, where are they?
Thanks,
try to put break point where you are creating your bean and run with debug mode, then you will find out whether your bean is created or not
You could define your own context for the test scope you are trying to run:
This would look something like:
public class TestApplicationContext implements ApplicationContextAware {
private static ApplicationContext context;
#Override
public void setApplicationContext(final ApplicationContext context) throws
BeansException {
TestApplicationContext.context = context;
}
public static Object getBean(final String beanName) {
return context.getBean(beanName);
}
}
Then you can create a bean for the context in a #Configuration annotated class.
#Bean
public TestApplicationContext testApplicationContext() {
return new TestApplicationContext();
}
Then you can easily reference whatever bean you need by simply:
TestApplicationContext.getBean("someBean");
I am trying to inject a prototype bean in a singleton bean such that every new call to a singleton bean method has a new instance of the prototype bean.
Consider a singleton bean as below:
#Component
public class SingletonBean {
#Autowired
private PrototypeBean prototypeBean;
public void doSomething() {
prototypeBean.setX(1);
prototypeBean.display();
}
}
I expect that every time the doSomething() method is called, a new PrototypeBean instance is utilized.
Below is the prototype bean:
#Component
#Scope(value="prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class PrototypeBean {
Integer x;
void setX(Integer x) {
this.x = x;
}
void display() {
System.out.println(x);
}
}
What seems to be happening is that spring is being overeager in handing over a new instance of PrototypeBean in the doSomething() method. That is, the 2 lines of code in the doSomething() method are creating a new instance of prototypeBean in each line.
And so in the 2nd line - prototypeBean.display() prints NULL.
What is missing in configuration for this injection?
From Spring documentation:
You do not need to use the <aop:scoped-proxy/> in conjunction with
beans that are scoped as singletons or prototypes. If you try to
create a scoped proxy for a singleton bean, the BeanCreationException
is raised.
It seems the documentation has changed a bit for version 3.2 documentation where you can find this sentence:
You do not need to use the <aop:scoped-proxy/> in conjunction with
beans that are scoped as singletons or prototypes.
It seems that its not expected you use a proxied prototype bean, as each time it is requested to the BeanFactory it will create a new instance of it.
In order to have a kind of factory for your prototype bean you could use an ObjectFactory as follows:
#Component
public class SingletonBean {
#Autowired
private ObjectFactory<PrototypeBean> prototypeFactory;
public void doSomething() {
PrototypeBean prototypeBean = prototypeFactory.getObject();
prototypeBean.setX(1);
prototypeBean.display();
}
}
and your prototype bean would be declared as follows:
#Component
#Scope(value="prototype")
public class PrototypeBean {
// ...
}
Singleton bean is created only once so the prototype bean which is injected also will be created once at the instantiation of singleton bean.The same instance of prototype bean will be used for every request.
If new instance of prototype bean will be created for each request at runtime ,the below method Injection can be used
Example
public class Singleton {
private Prototype prototype;
public Singleton(Prototype prototype) {
this.prototype = prototype;
}
public void doSomething() {
prototype.foo();
}
public void doSomethingElse() {
prototype.bar();
}
}
public abstract class Singleton {
protected abstract Prototype createPrototype();
public void doSomething() {
createPrototype().foo();
}
public void doSomethingElse() {
createPrototype().bar();
}
}
<bean id="prototype" class="ch.frankel.blog.Prototype" scope="prototype" />
<bean id="singleton" class="sample.MySingleton">
<lookup-method name="createPrototype" bean="prototype" />
</bean>
Right way to achieve it - use lookup method injection and everywhere where you used beans use lookup method invocation (detailed answer)
Since Spring 4.1 you can use annotation #Lookup
#Lookup
public PrototypeBean getPrototypeBean() {
return null;
}
Every time you will call method getPrototypeBean() - you will receive new prototype bean instance.
Don't worry about empty method realization: Spring will override it for you.
Read more in official documentation.
Spring wires up your beans in a pretty straight forward way. I'm working in a large commercial application, and I inserted the following code snippets to verify the load order.
1) All of your singleton bean class structures are initially loaded by Spring (as long as Spring is aware of them via annotations and/or xml). This only ever happens once. You can test this by logging or printing in a static block:
static {
log.info("#### classNameHere loaded"); //or println if no log setup
}
2) Spring creates all singleton instances that it is aware of (but not prototypes! Prototype instances WILL be created IF they are referenced inside a singleton bean - there class structures are of course loaded first). You can test this by adding this method to each class:
#PostConstruct
public void methodHitAfterClassInstantiation() {
LOGGER.info("#### instance of classNameHere");
}
So in your example, the class structures of SingletonBean is loaded when Spring starts up. A new instance of SingletonBean is created.
And because PrototypeBean is Autowired inside of SingletonBean, its class structure is loaded and an instance of it is created. Now, if there was another bean, say AnotherSingletonBean, with an Autowired PrototypeBean inside
of it, then a DIFFERENT instance of PrototypeBean would be created (no need to load the class structure again). So there is only ever 1 SingletonBean, and inside of it is a PrototypeBean, which
will always point to the same bean. Because of this, singletons should always be stateless, as all of your other beans that use a singleton will be pointing at the
same object. But you CAN maintain state in a prototype bean, because wherever you create a new reference, you will be pointing at another bean object.
http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-factory-scopes-prototype
I may be wrong here , but i am unable to figure out why is Spring creating 2 different objects from a Singleton class. Following is the code:
public class DbSingleTOn {
private static DbSingleTOn dbSingleTOn = new DbSingleTOn();
private DbSingleTOn() {
}
public static DbSingleTOn getInstance() {
return dbSingleTOn;
}
}
public class MyApp {
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext(
"spring-singleton.xml");
DbSingleTOn dbSingleTOn = context.getBean(DbSingleTOn.class);
System.out.println(dbSingleTOn.hashCode());
DbSingleTOn dbSingleTOn1 = context.getBean(DbSingleTOn.class);
System.out.println(dbSingleTOn1.hashCode());
context.registerShutdownHook();
}
}
Output:
18885489
17045421
Spring Config XML:
<bean id="bean1" class="com.singleton.DbSingleTOn" scope="prototype" >
</bean>
It is expected to get different object for a normal class using "prototype" scope, however, Why would "prototype" create 2 objects from Singleton class ?
Just because you create a singleton in a static field this does not have an impact on spring. Spring is simply not aware of that.
Prototype scope just means: return a new instance when getBean is called.
Singleton scope means: create an instance once and always return this one.
Two things. One, Spring has no idea (and really doesn't care) how your class is setup. The fact that you've implemented a programming pattern means nothing to Spring. Two, Spring uses reflection to instantiate the bean types you declare and therefore can use your private constructors.
Every time you request a prototype scoped bean from Spring, it will create a new instance of the bean.
If you don't setup directly how to instantiate the bean, Spring use reflection to call a constructor for create beans. In addition use of default singleton scope, you can also setup factory-method in your xml config to getInstance to tell Spring how to create your beans.
I am trying to inject a prototype bean in a singleton bean such that every new call to a singleton bean method has a new instance of the prototype bean.
Consider a singleton bean as below:
#Component
public class SingletonBean {
#Autowired
private PrototypeBean prototypeBean;
public void doSomething() {
prototypeBean.setX(1);
prototypeBean.display();
}
}
I expect that every time the doSomething() method is called, a new PrototypeBean instance is utilized.
Below is the prototype bean:
#Component
#Scope(value="prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class PrototypeBean {
Integer x;
void setX(Integer x) {
this.x = x;
}
void display() {
System.out.println(x);
}
}
What seems to be happening is that spring is being overeager in handing over a new instance of PrototypeBean in the doSomething() method. That is, the 2 lines of code in the doSomething() method are creating a new instance of prototypeBean in each line.
And so in the 2nd line - prototypeBean.display() prints NULL.
What is missing in configuration for this injection?
From Spring documentation:
You do not need to use the <aop:scoped-proxy/> in conjunction with
beans that are scoped as singletons or prototypes. If you try to
create a scoped proxy for a singleton bean, the BeanCreationException
is raised.
It seems the documentation has changed a bit for version 3.2 documentation where you can find this sentence:
You do not need to use the <aop:scoped-proxy/> in conjunction with
beans that are scoped as singletons or prototypes.
It seems that its not expected you use a proxied prototype bean, as each time it is requested to the BeanFactory it will create a new instance of it.
In order to have a kind of factory for your prototype bean you could use an ObjectFactory as follows:
#Component
public class SingletonBean {
#Autowired
private ObjectFactory<PrototypeBean> prototypeFactory;
public void doSomething() {
PrototypeBean prototypeBean = prototypeFactory.getObject();
prototypeBean.setX(1);
prototypeBean.display();
}
}
and your prototype bean would be declared as follows:
#Component
#Scope(value="prototype")
public class PrototypeBean {
// ...
}
Singleton bean is created only once so the prototype bean which is injected also will be created once at the instantiation of singleton bean.The same instance of prototype bean will be used for every request.
If new instance of prototype bean will be created for each request at runtime ,the below method Injection can be used
Example
public class Singleton {
private Prototype prototype;
public Singleton(Prototype prototype) {
this.prototype = prototype;
}
public void doSomething() {
prototype.foo();
}
public void doSomethingElse() {
prototype.bar();
}
}
public abstract class Singleton {
protected abstract Prototype createPrototype();
public void doSomething() {
createPrototype().foo();
}
public void doSomethingElse() {
createPrototype().bar();
}
}
<bean id="prototype" class="ch.frankel.blog.Prototype" scope="prototype" />
<bean id="singleton" class="sample.MySingleton">
<lookup-method name="createPrototype" bean="prototype" />
</bean>
Right way to achieve it - use lookup method injection and everywhere where you used beans use lookup method invocation (detailed answer)
Since Spring 4.1 you can use annotation #Lookup
#Lookup
public PrototypeBean getPrototypeBean() {
return null;
}
Every time you will call method getPrototypeBean() - you will receive new prototype bean instance.
Don't worry about empty method realization: Spring will override it for you.
Read more in official documentation.
Spring wires up your beans in a pretty straight forward way. I'm working in a large commercial application, and I inserted the following code snippets to verify the load order.
1) All of your singleton bean class structures are initially loaded by Spring (as long as Spring is aware of them via annotations and/or xml). This only ever happens once. You can test this by logging or printing in a static block:
static {
log.info("#### classNameHere loaded"); //or println if no log setup
}
2) Spring creates all singleton instances that it is aware of (but not prototypes! Prototype instances WILL be created IF they are referenced inside a singleton bean - there class structures are of course loaded first). You can test this by adding this method to each class:
#PostConstruct
public void methodHitAfterClassInstantiation() {
LOGGER.info("#### instance of classNameHere");
}
So in your example, the class structures of SingletonBean is loaded when Spring starts up. A new instance of SingletonBean is created.
And because PrototypeBean is Autowired inside of SingletonBean, its class structure is loaded and an instance of it is created. Now, if there was another bean, say AnotherSingletonBean, with an Autowired PrototypeBean inside
of it, then a DIFFERENT instance of PrototypeBean would be created (no need to load the class structure again). So there is only ever 1 SingletonBean, and inside of it is a PrototypeBean, which
will always point to the same bean. Because of this, singletons should always be stateless, as all of your other beans that use a singleton will be pointing at the
same object. But you CAN maintain state in a prototype bean, because wherever you create a new reference, you will be pointing at another bean object.
http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-factory-scopes-prototype
In my program I need to programmatically configure an ApplicationContext. Specifically, I have a reference to an instance of MyClass and I want to define it as a new bean called "xxyy".
public void f(MyClass mc, ApplicationContext ac) {
// define mc as the "xxyy" bean on ac ???
...
...
// Now retrieve that bean
MyClass bean = (MyClass) ac.getBean("xxyy");
// It should be the exact same object as mc
Assert.assertSame(mc, bean);
}
The BeanDefinition API let's me specify the class of the new bean, so it does not work for me since I want to specify the instance.
I managed to find a solution but it took two additional factory beans which seems like too much code for such an eartly purpose.
Is there a standard API that addresses my needs?
You need to jump through a few hoops to do this. The first step is to obtain a reference to the context's underlying BeanFactory implementation. This is only possible if your context implements ConfigurableApplicationContext, which most of the standard ones do. You can then register your instance as a singleton in that bean factory:
ConfigurableApplicationContext configContext = (ConfigurableApplicationContext)appContext;
SingletonBeanRegistry beanRegistry = configContext.getBeanFactory();
beanRegistry.registerSingleton("xxyy", bean);
You can "insert" any object into the context like this.
you can use this context:
GenericApplicationContext mockContext = new GenericApplicationContext();
which has a
mockContext.getBeanFactory().registerSingleton("name", reference);
and plug it in the real context
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
new String[] { "real-context.xml" }, mockContext);
and the classes are:
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.GenericApplicationContext;