Spring @Configuration vs @Component

一、介绍

从@Configuration的定义来看,@Configuration被@Component注解了,因此被@Configuration注解的类也会被加入到容器中,但是@Configuration配合@Bean还有其他的作用。下面看看官方文档介绍:

That said, there is a ‘lite’ mode of @Bean processing where we don’t apply any CGLIB processing: simply declare your @Bean methods on classes not annotated with @Configuration (but typically with another Spring stereotype instead, e.g. @Component). As long as you don’t do programmatic calls between your @Bean methods, this is going to work just as fine.

就是说@Bean在@Configuration中定义bean,会使用CGIB处理,因此可以@Bean方法中可以调用其他@bean方法,每次该bean方法产生的都是同一个Bean,维护他的singleton范围(Scope)。而Component不会,在@Bean方法中调用会产生多个Bean,尽管是singleton范围的。实际情况是这样的吗?。。。呵呵,当然不是。。。

二、实例代码

看看下面代码:

@Configuration
public static class Config {

    @Bean
    public SimpleBean simpleBean() {
        return new SimpleBean();
    }

    @Bean
    public SimpleBeanConsumer simpleBeanConsumer() {
        return new SimpleBeanConsumer(simpleBean());
    }
}
@Component
public static class Config {

    @Bean
    public SimpleBean simpleBean() {
        return new SimpleBean();
    }

    @Bean
    public SimpleBeanConsumer simpleBeanConsumer() {
        return new SimpleBeanConsumer(simpleBean());
    }
}

第一块代码如果运行正常,SimpleBeanConsumer会得到单实例SimpleBean,但是哦,用eclipse运行下,发现根本不是单实例SimpleBean。因为CGIB没有正常工作,稍后解释。

第二块代码中,Spring不能控制Bean的实例过程,只是接受方法的返回值,然后注册为bean而已。因此在simpleBeanConsumer方法中创建了另一个SimpleBean实例。

三、@Configuration中的@Bean方法执行的实际过程。

在@Configuration中,所有的被@Bean注解的方法都会包装成CGIB包装类,调用@Bean方法实际是调用了该包装类的方法。这个方法主要干了什么呢?下面是spring文档的原话:

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

也就是说,执行原先的@Bean方法时先测查一下有没有缓存的bean,在singleton范围内,则会直接返回该Bean,因此不会出现两个singleton范围的Bean,维护了singleton的范围。但是由于某种原因,CGIB没有正常工作,因此测试中和@Component没啥区别。具体原因请看这篇文章:CGLIB: signer information does not match signer information of other classes,大致原因就是spring的jar包是有签名的,我们的代码在没有打包、签名、部署之前是没有签名的,因此默认类加载器在验证时就出错了。

四、@Component代码修正

第二块代码没有维护simpleBean单实例的范围,因为new SimpleBeanConsumer(simpleBean())就是被单纯的调用了一下,可以通过下面的代码修正:

@Component
public static class Config {
    @Autowired
    SimpleBean simpleBean;

    @Bean
    public SimpleBean simpleBean() {
        return new SimpleBean();
    }

    @Bean
    public SimpleBeanConsumer simpleBeanConsumer() {
        return new SimpleBeanConsumer(simpleBean);
    }
}

参考:

http://dimafeng.com/2015/08/29/spring-configuration_vs_component/

http://dimafeng.com/2015/08/16/cglib/

猜你喜欢

转载自blog.csdn.net/jdbdh/article/details/82795049
今日推荐