Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

@Bean annotation on a static method

Tags:

spring

Can anyone explain me why a @Bean on a static method is returning 2 different instances ?

I can understand that @Bean on a method non static like the class A is returning the same instance because default scope is singleton.

And If I try to inject the class B with @Autowire in a Service it won't work, so it looks like it's not load by the Spring App Context. So using a class like D will be similar !? I think not because for @PropertySource we need to use in addition (used for the placeholder):

@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
    return new PropertySourcesPlaceholderConfigurer();
}

and if we remove @Bean from this, it won't work.

Is there other use case where it would be useful to use @Bean on a static method?

EXAMPLE:

when I run:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {Conf.class})
public class Test {
    @org.junit.Test
    public void test(){
    }
}

for

@Configuration
@ComponentScan
public class Conf {

    @Bean
    public A aaa(){
        return new A();
    }

    @Bean
    public static B bbb(){
        return new B();
    }

    @Bean
    @Scope("prototype")
    public C ccc(){
        return new C();
    }

    public static D ddd(){
        return new D();
    }

    @PostConstruct
    public void post(){
        System.out.println(aaa());
        System.out.println(aaa());
        System.out.println(bbb());
        System.out.println(bbb());
        System.out.println(ccc());
        System.out.println(ccc());
        System.out.println(ddd());
        System.out.println(ddd());
    }

}
public class A {
}
public class B {
}
public class C {
}
public class D {
}

I get:

uk.co.xxx.unit.A@6caf0677
uk.co.xxx.unit.A@6caf0677
uk.co.xxx.unit.B@413d1baf
uk.co.xxx.unit.B@16eb3ea3
uk.co.xxx.unit.C@353352b6
uk.co.xxx.unit.C@4681c175
uk.co.xxx.unit.D@57a78e3
uk.co.xxx.unit.D@402c4085
like image 468
Emilien Brigand Avatar asked Jun 16 '15 17:06

Emilien Brigand


People also ask

Can we use @bean with static method?

@Bean annotated methods get proxied in order to provide the correct bean instance. Static methods do not get proxied. Hence in your case bbb() invocation each time gives a new instance of B. PropertySourcesPlaceholderConfigurer class is a special kind of bean since it implements BeanFactoryPostProcessor.

Where we can use @bean on method?

Spring @Bean Annotation is applied on a method to specify that it returns a bean to be managed by Spring context. Spring Bean annotation is usually declared in Configuration classes methods. In this case, bean methods may reference other @Bean methods in the same class by calling them directly.

How do you call a Spring bean from a static method?

Usage in your static class would therefore just be: MyBean myBean = MyBean. get();

Is @bean and @component same?

@Component is a class-level annotation, but @Bean is at the method level, so @Component is only an option when a class's source code is editable. @Bean can always be used, but it's more verbose. @Component is compatible with Spring's auto-detection, but @Bean requires manual class instantiation.


2 Answers

Because you create a new object for every method call to bbb(). Inter-bean dependencies (if you just call the bean producing method) work in that way, that a proxy is created for your configuration class, and the proxy intercepts method calls to the bean methods to deliver the correct bean (singleton, prototype etc.). However, static methods are not proxied, so when you call the static method, Spring doesn't know about it and you just get the regular Java object. With the PropertySourcesPlaceholderConfigurer it is different, because that method isn't directly called in that class, the bean will only be injected where it is used.

like image 175
dunni Avatar answered Sep 22 '22 17:09

dunni


@Bean annotated methods get proxied in order to provide the correct bean instance. Static methods do not get proxied. Hence in your case bbb() invocation each time gives a new instance of B.

PropertySourcesPlaceholderConfigurer class is a special kind of bean since it implements BeanFactoryPostProcessor. In the container lifecycle, a BeanFactoryPostProcessor object must be instantiated earlier than an object of @Configuration-annotated class. Also you don't need to call this static method.

See Bootstrapping section in the java doc : [http://docs.spring.io/spring/docs/4.2.x/javadoc-api/org/springframework/context/annotation/Bean.html][1]

Special consideration must be taken for @Bean methods that return Spring BeanFactoryPostProcessor (BFPP) types. Because BFPP objects must be instantiated very early in the container lifecycle, they can interfere with processing of annotations such as @Autowired, @Value, and @PostConstruct within @Configuration classes. To avoid these lifecycle issues, mark BFPP-returning @Bean methods as static

like image 25
Inv3r53 Avatar answered Sep 21 '22 17:09

Inv3r53