4

I created a spring bean in a configuration class like this:

@Bean
MyClass getMyClass() {
    MyClass mc = new MyClass()
    return mc;
}

Whenever MyClass is autowired in another class that needs it injected, will it always create a new object by virtue of new in bean definition? Is a bean created this way a real singleton ?

Lemmy
  • 2,437
  • 1
  • 22
  • 30
Hary
  • 1,127
  • 4
  • 24
  • 51

3 Answers3

4

Spring guarantees that whatever you do in the method annotated with Bean annotation it will be done only once. Internal Spring factories will take care about that.

Of course it depends from scope but by default scope is singleton. See docs:

  1. Scopes
  2. Bean
  3. Is spring default scope singleton or not?

Small example which should help you to understand how it works:

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.time.LocalDateTime;
import java.util.Random;

@Configuration
public class SpringApp {

    public static void main(String[] args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringApp.class);

        System.out.println(ctx.getBean(MyClass.class));
        System.out.println(ctx.getBean(MyClass.class));
        System.out.println(ctx.getBean(MyClass.class));
        System.out.println(ctx.getBean(MyClass.class));
    }

    @Bean
    public MyClass getMyClass() {
        System.out.println("Create instance of MyClass at " + LocalDateTime.now());
        MyClass myClass = new MyClass();

        return myClass;
    }
}

class MyClass {

    private int value = new Random().nextInt();

    @Override
    public String toString() {
        return super.toString() + " with values = " + value;
    }
}

prints:

Create instance of MyClass at 2019-01-09T22:54:37.025
com.celoxity.spring.MyClass@32a068d1 with values = -1518464221
com.celoxity.spring.MyClass@32a068d1 with values = -1518464221
com.celoxity.spring.MyClass@32a068d1 with values = -1518464221
com.celoxity.spring.MyClass@32a068d1 with values = -1518464221

When you define bean with scope protoype

@Scope("prototype")
@Bean
public MyClass getMyClass()

App prints:

Create instance of MyClass at 2019-01-09T22:57:12.585
com.celoxity.spring.MyClass@282003e1 with values = -677868705
Create instance of MyClass at 2019-01-09T22:57:12.587
com.celoxity.spring.MyClass@7fad8c79 with values = 18948996
Create instance of MyClass at 2019-01-09T22:57:12.587
com.celoxity.spring.MyClass@71a794e5 with values = 358780038
Create instance of MyClass at 2019-01-09T22:57:12.587
com.celoxity.spring.MyClass@76329302 with values = 868257220
Michał Ziober
  • 37,175
  • 18
  • 99
  • 146
0

In your example, yes.

What will happen practically is that when Spring starts up, it will call the getMyClass() method which will new up an instance of the object. Spring will then retain that single instance and inject it into all other beans that require an instance of MyClass.

It will work this way since you've not declared a scope on the bean -- the default is singleton as indicated by the other answer.

Roddy of the Frozen Peas
  • 14,380
  • 9
  • 49
  • 99
0

Spring's concept of a singleton bean is quite different from the Singleton pattern.

The scope of the Spring singleton is best described as per container and per bean

Section 4.4.1

This mean that if you create a spring bean, that bean provides its lifecycle from within the IoC Spring Container. If you want to create with "NEW really a singleton bean". You have this through a new Spring Ioc Container. Let me illustrate this through an example.

 public static void main(String[] args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringApp.class);
        ApplicationContext ctxReallyNewOne = new AnnotationConfigApplicationContext(SpringApp.class);
        ApplicationContext ctx2ReallySecondOne = new AnnotationConfigApplicationContext(SpringApp.class);

        System.out.println(ThreadColors.Red + "Beans created via same Ioc container with same class");
        System.out.println(ctx.getBean(MyClass.class));
        System.out.println(ctx.getBean(MyClass.class));

        System.out.println(ThreadColors.Cyan + "Beans created via different Ioc container with SAME CLASS");
        System.out.println(ctxReallyNewOne.getBean(MyClass.class));
        System.out.println(ctx2ReallySecondOne.getBean(MyClass.class));

    }

After running this code, the following is written to the console.

enter image description here

Also if you want to get the creation date of a bean.Does not need to use LocalDataTime.now() . It is best practice to use "The Lifecycle of Spring Beans" for this.

The Lifecycle of Spring Beans

Yusuf BESTAS
  • 91
  • 1
  • 6