静态方法上的@Bean注释

时间:2015-06-16 17:26:48

标签: spring

任何人都可以解释为什么静态方法上的@Bean返回2个不同的实例?

我可以理解,类@Bean之类的非静态方法的A返回相同的实例,因为默认范围是单例。

如果我尝试在服务中使用B注入类@Autowire它将无法工作,所以看起来它不是由Spring App Context加载的。所以使用像D这样的类会是类似的! 我想不是因为@PropertySource我们需要另外使用(用于占位符):

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

如果我们从中删除@Bean,它将无效。

是否存在其他用例,在静态方法上使用@Bean会很有用?

实施例

我跑的时候:

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

@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 {
}

我明白了:

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

2 个答案:

答案 0 :(得分:8)

因为您为bbb()的每个方法调用创建了一个新对象。 bean之间的依赖关系(如果你只是调用bean生成方法)以这种方式工作,为你的配置类创建一个代理,并且代理拦截对bean方法的方法调用以提供正确的bean(单例,原型等)。 )。但是,静态方法不会被代理,因此当您调用静态方法时,Spring并不知道它,您只需获取常规Java对象。使用PropertySourcesPlaceholderConfigurer它是不同的,因为该方法不是在该类中直接调用的,bean只会在使用它的地方注入。

答案 1 :(得分:3)

@Bean注释方法获取代理以提供正确的bean实例。静态方法不会被代理。因此,在您的情况下,每次bbb()调用都会给出一个新的B实例。

PropertySourcesPlaceholderConfigurer类是一种特殊的bean,因为它实现了BeanFactoryPostProcessor。在容器生命周期中,BeanFactoryPostProcessor对象必须早于@Configuration-annotated类的对象进行实例化。此外,您不需要调用此静态方法。

请参阅java doc中的Bootstrapping部分:[http://docs.spring.io/spring/docs/4.2.x/javadoc-api/org/springframework/context/annotation/Bean.html][1]

  

必须特别考虑返回的@Bean方法   Spring BeanFactoryPostProcessor(BFPP)类型。因为BFPP对象   必须在容器生命周期的早期实例化,他们可以   干扰注释的处理,如@Autowired,@ Value,   和@Configuration类中的@PostConstruct。避免这些   生命周期问题,标记BFPP - 将@Bean方法返回为静态