@Configuration和@Component注册的@Bean

文章目录

    • 0. 区别
    • 1. @Bean的注册原理和过程
    • 2. CGLIB内部方法调用:

0. 区别

直接讲一下区别:
在配置类的方法间调用时,如果类时@component标注的,每次调用获取的都是新的实体;而如果是@configuration标注的话,每次调用返回的是同一个实体Bean。其他方面都是相同,可以无差别使用(装配注入等)。看一下代码可能更加清晰一点:

@Configuration和@Component注册的@Bean_第1张图片
@Configuration和@Component注册的@Bean_第2张图片

哪是什么原因造成的呢?不卖关子,是因为@Configuration标注下的@Bean调用函数使用都是代理对象,获取的都是从IOC容器里获取的bean,因此都是同一个。而@Component标注下的@Bean下只是普通的函数方法调用。下面来看一下@configuration注册@Bean生成代理的过程。

1. @Bean的注册原理和过程

其实再看@Enable***注解的实现原理的时候有提到。是在ConfigurationClassPostProcessor类中解析的:

@Configuration和@Component注册的@Bean_第3张图片

看一下注册的地方:

@Configuration和@Component注册的@Bean_第4张图片

然后是生成代理的地方和生成代理拦截方法:

public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
     
        Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<String, AbstractBeanDefinition>();
        for (String beanName : beanFactory.getBeanDefinitionNames()) {
     
            BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
            if (ConfigurationClassUtils.isFullConfigurationClass(beanDef)) {
       // 只有带@Configuration注解的类才会被代理
                if (!(beanDef instanceof AbstractBeanDefinition)) {
     
                    throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +
                            beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
                }
                else if (logger.isWarnEnabled() && beanFactory.containsSingleton(beanName)) {
     
                    logger.warn("Cannot enhance @Configuration bean definition '" + beanName +
                            "' since its singleton instance has been created too early. The typical cause " +
                            "is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +
                            "return type: Consider declaring such methods as 'static'.");
                }
                configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
            }
        }
        if (configBeanDefs.isEmpty()) {
     
            // nothing to enhance -> return immediately
            return;
        }
        ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer(); // 增强类,内有增强方法..(省略代码)
    }

可以看到只有被@Configuration注解标识的类才会被增强。看一下增强类和设置的callBack。
@Configuration和@Component注册的@Bean_第5张图片
@Configuration和@Component注册的@Bean_第6张图片

BeanMethodInterceptor会根据方法名去IOC找到Bean并返回,具体代码就不贴了。

2. CGLIB内部方法调用:

@Configuration和@Component注册的@Bean_第7张图片

看一下getObjectMethod字节码:

 0 getstatic #2 <java/lang/System.out>
 3 ldc #6 <getObjectMethod>
 5 invokevirtual #4 <java/io/PrintStream.println>
 8 aload_0
 9 invokevirtual #7 <com/study/h/config/testConfigurationBean/enhancer/EnhancerModel.getObject>
12 areturn

可以看到getObjectMethod方法中的getObject()方法仍旧会通过代理对象调用getObject方法。

你可能感兴趣的:(springBoot相关,java,springboot,@bean)