I have a graph of Spring beans which autowire each other. Heavily simplified illustration:
<context:annotation-config/>
<bean class="Foo"/>
<bean class="Bar"/>
<bean class="Baz"/>
...
public class Foo {
#Autowired Bar bar;
#Autowired Baz baz;
}
public class Bar {
#Autowired Foo foo;
}
public class Baz {
#Autowired Foo foo;
}
All of these beans don't have scope specified which imply they are singletons (making them explicit singletons doesn't change anything, I've tried).
The problem is that after the instantiation of a single application context, instances of Bar and Baz contain different instances of Foo. How could this happen?
I have tried to create public no args constructor for Foo and debugging has confirmed Foo is created more than once. The stack trace for all of these creations is here.
I have also tried to enable debug logging for Spring, and among all other lines, got the following:
DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'Foo'
DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'Foo'
DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'Foo'
I understand that my beans are cross-referencing each other, but I would expect Spring framework to respect singleton scope and initialize a singleton bean once, and then autowire it to whoever wants it.
The interesting fact that if I use old school private constructor with public static Foo getInstance accessor, this works just fine - no exceptions are thrown during the context setup.
FWIW, I am using Spring version 3.0.5 (also tried with 3.1.2, same results) with o.s.c.s.ClassPathXmlApplicationContext(String ...configLocations) constructor.
I can easily convert my code to use static initializer but I want to understand why would Spring behave this way. Is this a bug?
EDIT: Some additional investigation showed that
After the application context is initialized, all subsequent requests to context.getBean(Foo.class) always return the same instance of Foo.
Replacing #Autowired with setters (about 20 usages of this bean) still results multiple constructions of this object, but all dependencies are injected with the same reference.
To me above suggests that this is a Spring bug pertaining to #Autowired implementation. I am going to post to Spring community forums and post back here if I manage to obtain anything useful.
Child context(s) can reinstantiate the same singleton beans if you are not careful with context:component-scan annotations (there are other Spring context scan annotations as well such as MVC ones and others). This is a common problem when using Spring servlets in web applications, see Why DispatcherServlet creates another application context?
Make sure you are not re-scanning your components in child contexts, or you are scanning only specific packages/annotations and excluding said packages/annotations from root context component scan.
For some reason we are getting this popping up randomly in integration tests and services as well (spring version 4.1.4, java 1.8).
Looks like there might be more than one culprit - Autowiring appeared to be causing this at first.
However, we have resolved the most consistent failures by ensuring we give each impacted bean an 'id' field.
Try using setter injection instead of constructor way and see if it works.In the spring bean xml specify Bean A ref to Bean B and vice versa.
My Spring configuration was like follows:
<context:annotation-config/>
<bean class="Bar" />
<bean class="Foo" />
<bean class="Baz" />
Classes are identical to yours
Test app like follows:
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringTest {
/**
* #param args
*/
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("META-INF/spring/testctx.xml");
Foo foo = ctx.getBean(Foo.class);
Baz baz = ctx.getBean(Baz.class);
Bar bar = ctx.getBean(Bar.class);
System.out.println(foo.equals(baz.foo));
System.out.println(foo.equals(bar.foo));
System.out.println(baz.equals(foo.baz));
System.out.println(foo.baz.toString());
System.out.println(baz.toString());
System.out.println(foo.bar.toString());
System.out.println(bar.toString());
}
}
Output from test app like follows:
true
true
true
Baz#8aef2b
Baz#8aef2b
Bar#215bf054
Bar#215bf054
Using 3.0.6 it works perfectly fine (singleton beans are indeed singletons). There might be something else you did not illustrate here messing up your configuration. Of course, as a side note, using default package may cause some misterious magic to happen ;-)
Related
I am writing a spring application which is interactive and basically handles lots of commands like create, list, update, delete various types of resources.
For now, just assume a single run of the application handles only a single command and the program exits.
For all the classes to validate command, execute the command, required factory classes for each resource there is a separate class and each class is annotated with #Component annotation for spring to manage all the components.
There are also some of the manually defined beans by #Bean method.
Now that my application first identifies what kind of command is executed (create, delete, list, update, etc), I want the only beans of that command to be created and Autowired wherever required (after taking command from user) and I want to avoid the creation of dozens of beans related to other commands.
On searching, I came to know about Lazy instantiation of Beans that spring provides.
However, I am not sure if it is the weapon I am searching for.
What I tried
Very first I found #Lazy annotation, but since I want to lazily load all the Beans, I don't want to write #Lazy everywhere in each class.
Then I found setting below property in application.yml does the work.
spring:
main:
lazy-initialization: true
I tried that but still, it is not lazily creating the beans.
My application.yml files looks like this
spring:
main:
lazy-initialization: true
My main SpringBootApplication file looks like this:
#Slf4j
#SpringBootApplication
public class SpringBootApplication {
public static void main(String[] args) {
System.out.println("Loading Application...");
ApplicationContext context = SpringApplication.run(SpringBootApplication.class, args);
final AtomicInteger counter = new AtomicInteger(0);
log.info("**************** START: Total Bean Objects: {} ******************", context.getBeanDefinitionCount());
Arrays.asList(context.getBeanDefinitionNames())
.forEach(beanName -> {
log.info("{}) Bean Name: {} ", counter.incrementAndGet(), beanName);
});
log.info("**************** END: Total Bean: {} ******************", context.getBeanDefinitionCount());
}
}
My other classes looks like this:
#Component
#RequiredArgsConstructor(onConstructor = #__(#Autowired))
public class MyClass1 implements ResourceCreator<MyClass2, MyClass3> {
private final RequestValidatorImpl requestValidator;
private final ResourceCreator resourceCreator;
#Override
public MyClass2 toImplementFunction(MyClass3 myclass3) {
//logic
}
On running the application, It prints all the classes where I annotated #Component as well as beans created by #Bean method.
I have also tried using below in Application.properties but still no use.
spring.main.lazy-initialization=true
Also, if you wish, please comment on whether I should use #Component for each Class like I am using or not and what is better practice instead.
I think you misunderstood the meaning of the lazy flag you are passing,
It means that the object will be created only when it is invoked but it does not say that it will not scan that package. Spring will scan all packages and store bean definition names but it will create the objects only when it is invoked, if you have passed the lazy flag to it.
You can verify this behaviour by checking the number of beans created when you pass the lazy flag as true and false.
you can check it as given below
ApplicationContext context = SpringApplication.run(SpringBootApplication.class, args);
System.out.println("count:"+context.getBeanDefinitionCount());
Edit on Apr/7th 2020 start
Another way to do that is create a constructor and use that to inject the autowired properties and print out a log when they enter the constructor.
I did the same in a sample project and below is he result, first one is for eager initialization and next one for lazy.
spring.main.lazy-initialization=false
Application logs
Inside Constructor
calling bean
inside bean method
spring.main.lazy-initialization=true
Application logs
calling bean
Inside Constructor
inside bean method
Edit on Apr/7th 2020 end
Please mark this as answered if I answered your question.
Thank you
Long story short:
For anyone wanting to lazily initialize their whole Spring Boot context, setting this property to true is the way to go:
spring.main.lazy-initialization=true
Pro tip:
It can be used in combination with the #Lazy annotation, set to false; so all the defined beans will use lazy initialization, except for those that we explicitly configure with #Lazy(false).
In such a way, the lazy initialization becomes opt-out instead of the default opt-in.
Could you please explain why Spring is creating two objects for the configuration of beans shown below, since by default spring default scope is singleton?
The Spring configuration is here:
<bean id="customer" class="jp.ne.goo.beans.Customer">
<property name="custno" value="100"></property>
<property name="custName" value="rajasekhar"> </property>
</bean>
<bean id="customer2" class="jp.ne.goo.beans.Customer">
<property name="custno" value="200"></property>
<property name="custName" value="siva"></property>
</bean>
Spring's default scope is singleton. It's just that your idea of what it means to be a singleton doesn't match how Spring defines singletons.
If you tell Spring to make two separate beans with different ids and the same class, then you get two separate beans, each with singleton scope. All singleton scope means is that when you reference something with the same id, you get the same bean instance back.
Here is how the Spring documentation defines singleton scope:
Only one shared instance of a singleton bean is managed, and all requests for beans with an id or ids matching that bean definition result in that one specific bean instance being returned by the Spring container.
Singleton scope means using the same id retrieves the same bean, that is all. Testing that no two ids referenced the same class would get in the way of using maps as beans, and would be complicated by proxying things with BeanFactories.
For Spring to police this would involve a lot of work for little benefit. Instead it trusts the users to know what they're doing.
If you want a bean’s singleton-ness preserved across multiple names, that is do-able. You can have more than one name refer to the same bean, that is done by using an alias:
In a bean definition itself, you can supply more than one name for the bean, by using a combination of up to one name specified by the id attribute, and any number of other names in the name attribute. These names can be equivalent aliases to the same bean, and are useful for some situations, such as allowing each component in an application to refer to a common dependency by using a bean name that is specific to that component itself.
Specifying all aliases where the bean is actually defined is not always adequate, however. It is sometimes desirable to introduce an alias for a bean that is defined elsewhere. This is commonly the case in large systems where configuration is split amongst each subsystem, each subsystem having its own set of object definitions. In XML-based configuration metadata, you can use the element to accomplish this.
So if you add a name in the bean configuration:
<bean id="customer" name="customer2"
class="jp.ne.goo.beans.Customer">
</bean>
or create an alias for a bean defined elsewhere:
<alias name="customer" alias="customer2"/>
then "customer" and "customer2" will refer to the same bean instance.
Spring default scope is singleton and it will create one object for all instances unless you explicitly specify the scope to be prototype. You have not posted spring configuration. Please post it, it will give a better idea.
In Spring Singleton refers to One bean per Spring container where as in Java Singleton refers to one object per class loader.
So Spring singleton is not same as java singleton. Don't get confused between these two.
You're confusing two different concepts.
The word singleton in spring is used for a bean scope, meaning that the bean will be created only once for the whole application.
Singleton usual meaning refers to the GOF pattern. It is an object oriented pattern guarantying that only one instance of a class will exists (at least in the scope of the classLoader).
You are declaring two beans of the same class. That isn't the same.
#Component("springTestClass")
public class SpringTestClass{
private int randomNumber = 0;
public SpringTestClass(){
randomNumber = new Random().nextInt(2000);
}
public int getRandomNumber(){
return this.randomNumber;
}
}
And try to access this bean in two places the number will be the same. But what you have done was creating two separate beans.
If you want to check if this works try:
public class Main{
public static void main(String[] args){
ApplicationContext ctx = ....;
SpringTestClass testObject1 = (SpringTestClass)ctx.getBean("springTestClass");
SpringTestClass testObject2 = (SpringTestClass)ctx.getBean("springTestClass");
System.out.println(testObject1.getRandomNumber() == testObject2.getRandomNumber());
}
}
This code should return true if it is same instance;
But in SpringTestClass you can add #Scope("prototype") annotation.
The output will be false
Like others have mentioned, two beans should be created from the code you posted. Singletons are defined as follows (from the Spring documentation: Singleton Scope)
Only one shared instance of a singleton bean is managed, and all requests for beans with an id or ids matching that bean definition result in that one specific bean instance being returned by the Spring container.
To add clarity to this, the meaning behind "shared instance" is explained in the paragraph that follows the one above:
all subsequent requests and references for that named bean return the cached object
When a singleton bean is created, only one bean object is instantiated and cached. This refers only to the bean, not to whatever class the bean may be an instance of. For example,
<bean id="myBean" class="myPackage.myClass" />
<bean id="myOtherBean1 class="myPackage.myOtherClass1">
<property name="beanReference1" ref="myBean" />
</bean>
<bean id="myOtherBean2 class="myPackage.myOtherClass2">
<property name="beanReference2" ref="myBean" />
</bean>
In this made up configuration, "myOtherBean1" and "myOtherBean2" have references to the same "myBean" bean therefore the same "myPackage.myClass" instance. If you changed the code to add a second "myPackage.myClass" bean, it would be distinct from "myBean".
To fully understand this, also refer to the other Spring scope: the prototype. From the Spring documentation for Prototype Scope:
The non-singleton, prototype scope of bean deployment results in the creation of a new bean instance every time a request for that specific bean is made.
This means that if we were to use the same Spring XML as above, "myOtherBean1" and "myOtherBean2" would each receive their own distinct copies of "myBean" which is still just an instance of "myPackage.myClass".
Spring Singleton Bean Does not work like Java Singleton.
If we write
ApplicationContext ctx = new ClassPathXmlApplicationContext("MyConfig.xml");
Customer obj1= (Customer) ctx.getBean("customer");
Customer obj2 = (Customer) ctx.getBean("customer2");
System.out.println(obj1 == obj2);
System.out.println(obj1+ "::" + obj2);
If we see the output it will return 2 different Instance.
According to Spring Docs
Bean is singleton only one shared Instance will be managed, and all request beans with an ID or ID matching that bean definition. Here 2 different ID is available.
Spring container as managing Key value pair, Key as ID/Name and value is bean.
The following example shows a #Bean annotated method being called
twice:
#Configuration
public class AppConfig {
#Bean
public ClientService clientService1() {
ClientServiceImpl clientService = new ClientServiceImpl();
clientService.setClientDao(clientDao());
return clientService;
}
#Bean
public ClientService clientService2() {
ClientServiceImpl clientService = new ClientServiceImpl();
clientService.setClientDao(clientDao());
return clientService;
}
#Bean
public ClientDao clientDao() {
return new ClientDaoImpl();
}
}
clientDao() has been called once in clientService1() and once in
clientService2(). Since this method creates a new instance of
ClientDaoImpl and returns it, you would normally expect having 2
instances (one for each service). That definitely would be
problematic: in Spring, instantiated beans have a singleton scope by
default. This is where the magic comes in: All #Configuration classes
are subclassed at startup-time with CGLIB. In the subclass, the child
method checks the container first for any cached (scoped) beans before
it calls the parent method and creates a new instance. Note that as of
Spring 3.2, it is no longer necessary to add CGLIB to your classpath
because CGLIB classes have been repackaged under
org.springframework.cglib and included directly within the spring-core
JAR.
spring default scope is singleton. Once the bean will be created and same bean used throughout its lifecycle.
A simple question that might have an advanced answer.
The Question:
My question is, is there a way to instantiate only the classes, in your application context, needed for that specific JUnit test ?
The Reason:
My application context is getting quite big. I also do a lot of integration tests so you I guess you would understand when I say that every time I run a test all the classes in my application context get instantiated and this takes time.
The Example:
Say class Foo inject only bar
public class Foo {
#Inject
Bar bar;
#Test
public void testrunSomeMethod() throws RegisterFault {
bar.runSomeMethod();
}
but the application context has beans foobar and bar. I know this is not a vaild application context but rest assure all my code works.
<beans>
<bean id="foobar" class="some.package.FooBar"/>
<bean id="bar" class="some.package.Bar"/>
<beans>
So how do I tell spring to only instantiate Bar and ignore FooBar for the test class foo.
Thank you.
Consider adding default-lazy-init="true" to your spring context xml beans tag (or add lazy-init="true" to those specific beans that take a long time starting up).
This will ensure that only those beans are created that called with applicationContext.getBean(class-or-bean-name) or injected via #Autowired / #Inject into your tests. (Some other types of beans like #Scheduled beans will be created nevertheless but you need to check if that's a problem or not)
(if you use spring Java configuration, add #Lazy to the config files)
Caveat - If there is a bean that is not initialized explicitly with applicationContext.getBean() or injected as a dependency used by the bean obtained by using applicationContext.getBean(), then that bean will NO LONGER be constructed or initialized. Depending upon your application, that can cause things to fail OR not. Maybe you can selectively mark those beans as lazy-init="false"
Yes, we can do that, using context per test case. Prepare a test context xml file with the beans required for your test case.
If you use maven, place the test-context.xml under src/test/resources folder.
Annotate your required test class with the following annotation
#ContextConfiguration(locations = "classpath:test-application-context.xml")
This helps in loading only specific beans for the test case.
If you have two kinds of test cases, then
#Runwith(SpringJUnit4Runner.class)
#ContextConfiguration(locations = "classpath:test-context-case1.xml")
public class TestClassCase1 {}
#Runwith(SpringJUnit4Runner.class)
#ContextConfiguration(locations = "classpath:test-context-case2.xml")
public class TestClassCase2 {}
It's not direct answer, so I'd would not mark as solution. But hope it's helpful.
Generally I see three options.
As VinayVeluri answered nicely. Create separate contexts and launch them in every tests separately.
Create context one time per all tests. Just like here: Reuse spring application context across junit test classes It's a big optimization for testing all tests at once.
Mix those two first points. Create one smaller context only for testing purpose. Mock that, what's never is tested but can throw NPE etc. Like here: Injecting Mockito mocks into a Spring bean to boost up context build. And re-use it like in point 2. One time build for all tests. Personally I'd go with that one.
This one waiting for answer about some kind of smart test runner, which creates minimum needed context per test.
In a modular Spring configured application, we use factory beans to provide bean instances across module boundaries.
For example, one module A may expose a bean instance by the name name. Another module B can then consume that bean via a declaration of the style
<bean id="nameBean" class="com.zfabrik.springframework.ComponentFactoryBean">
<property name="componentName" value="A/name" />
<property name="className" value="a.AInterface" />
</bean>
Note that modules have separated class loader hierarchies and the actual implementation class of A/name may not be visible in B. As if in OSGI (although this is NOT OSGi).
My goal is to provide A/name in a programmatic application context in B. However when trying
#Configuration
public static class AppContext {
#Bean AInterface nameBean() {
return lookup("A/name",AInterface.class);
}
}
(lookup does the actual instance retrieval) I see that Spring is trying to configure the returned instance. For example, it will attempt to resolve #Autowired properties of A/names's implementation class - which does not make sense in the context of B (and the deal of the lookup is to provide something fully configured anyway). Even, if I try
#Configuration
public static class AppContext {
#Bean(autowire=Autowire.NO) AInterface nameBean() {
return lookup("A/name",AInterface.class);
}
}
it will go about configuring the returned instance.
How can I provide a bean to the application context without spring touching its implementation instance?
EDIT: As suggested by Sotirios Delimanolis, returning the FactoryBean does AFAICT avoids Spring configuration of the returned instance.
The alternative code would look like this:
#Configuration
public static class AppContext {
#Bean FactoryBean<AInterface> nameBean() {
return new ComponentFactoryBean("A/name",AInterface.class);
}
}
It's not as cool as an #UntouchedBean annotation because of the FactoryBean in the return type, but it solves the problem.
#Sotirios: Please suggest as answer so that I can tag your suggestion accordingly.
/EDIT
Ok, just so it can be closed. The suggested and accepted answer is to return the factory bean.
I am studying for the Spring Core certification and I have some doubts related this questions:
In Spring are beans lazily or eagerly instantiated by default? How do
you alter this behavior?
So I know that the bean are eagerly instantiated by default by the Spring Container and I know that it automatically create my beans (declared into the configuration) in right order with its dependencies injected. And I know that after dependency injection each bean goes through a post-processing phase in which Further configuration and initialization may occur. So at the ending of this phase my beans are fully initialized and ready for use.
So I think that the meaning of eagerly beans instantiation is the behavior of the creation of the declared bean before the application start. Is it right or am I missing something?
At the contrary the lazy initialization is the tactic of delaying the creation of an object, the calculation of a value, or some other expensive process until the first time it is needed.
And so I have my first doubt about it. Is this the same behavior of a classi Java application (that don't use Spring) in which, at a certain point of the program execution, I declare a statment like this:
private void myMethod() {
....................................
....................................
....................................
DO SOMETHING
...................................
MyObject myObject = new MyObject(); // Is it lazily instantiated?
....................................
....................................
}
So in the case of the previous snippet is it the MyObject myObject lazily instantiated (this is not instantiated before that my application start but it is instantiated at certain pint of the application execution) or am I missing something?
By the way coming back at the original question: How can I alter the default behavior and how can I instantiate a bean in a lazily way?
Reading on the course documentation I found that Spring support Lazy beans ant it say this assertion:
Lazy beans are supported – only created when getBean() called. Not
recommended, often misused: #Lazy or <bean lazy-init=“true” ...>
So I thing to understand that (by I am not sure about it) that if into my Java code I do something like:
ApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Hello hello = (Hello) appContext.getBean("hello");
the bean having id hello is lazily instantiated. Is it true or is it wrong or missing something?
If it is true from what I can understand reading the previous documentation it is not a good idea use the previous solution (why?) but it is better to choose annotate the bean configuration (into the Java configuration class) that have to be lazily instantiated with the #Lazy annotation or use <bean lazy-init=“true” ...> into the XML configuration (of the bean).
So it means that #Lazy in Spring can be used inside #Configuration classes. The bean which has been declared with #Lazy annotation will not be initialized by spring container. #Lazy will be initialized by container only when that bean will be accessed somewhere in code.
Ok, but now my doubt is: how can I access to a bean that is not yet instantiated? Can you show me an example of it?