美文网首页
2021-02-25_Spring源码学习笔记@Configur

2021-02-25_Spring源码学习笔记@Configur

作者: kikop | 来源:发表于2021-02-25 08:04 被阅读0次

    Spring源码学习笔记@Configuration

    1概述

    本文基于Spring Framework版本5.0.0(最新版本5.3.4,SringBoot最新版本2.4.2。(参考文档: https://docs.spring.io/spring-boot/docs/current/api/)

    1.1Spring各个版本区别

    GA:General Availability,正式发布的版本,官方推荐使用此版本。在国外都是用GA来说明release版本的。

    PRE: 预览版,内部测试f版. 主要是给开发人员和测试人员测试和找BUG用的,不建议使用;

    SNAPSHOT: 快照版,可以稳定使用,且仍在继续改进版本。

    1.2 @Configuraion

    1.2.1注解作用

    Annotating a class with @Configuration indicates that its primary purpose is as a source of bean definitions. Furthermore, @Configuration classes let inter-bean dependencies be defined by calling other @Bean methods in the same class. The simplest possible @Configuration class reads as follows:

    中文的解释就是:

    @Configuration有两个作用:

    1. 表明其主要目的是作为Bean定义的来源。
    2. 此外,@Configuration类允许通过调用@Bean同一类中的其他方法来定义Bean之间的依赖关系。

    2代码示例

    2.1pom文件配置

    <dependencies>
    
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
    
        <!--2.spring对web的支持,依赖 spring-webmvc-->
        <!--此时jar包会自动下载(spring-context、spring-web、spring-webmvc)-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${springframework.version}</version>
        </dependency>
    
        <!--2.2.spring dao层依赖(jdbc 和 tx)-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${springframework.version}</version>
        </dependency>
    
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${springframework.version}</version>
        </dependency>
    
        <!--2.3.spring test相关依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${springframework.version}</version>
        </dependency>
    
    </dependencies>
    

    2.2 定义普通的pojo类

    2.3定义配置类

    package com.kikop.config;
    
    
    import com.kikop.model.MySchool;
    import com.kikop.model.MyUser;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    /**
     * @author kikop
     * @version 1.0
     * @project Name: myspringdemo
     * @file Name: AppConfig
     * @desc 可以实现基于Java的配置类加载Spring的应用上下文
     * @date 2021/2/14
     * @time 10:50
     * @by IDE: IntelliJ IDEA
     */
    // @Configuration:可理解为用spring的时候xml里面的<beans>标签,特别是Beans依赖是,确保被构造一次
    //@Configuration
    public class AppConfig_BeanDependency {
    
        @Bean
        public MySchool mySchool() {
            MySchool mySchool = new MySchool();
            mySchool.setName("hytc");
            System.out.println(mySchool);
            return mySchool;
        }
    
        @Bean
        public MyUser myUser() {
            // 这里测试 mySchool是否是单例Bean,实际是用了Spring的字节码增强代理技术。
            MySchool mySchool = mySchool();
            MyUser myUser = new MyUser();
            myUser.setUserName("kikop");
            return myUser;
        }
    
    }
    

    2.4测试

    private static void AppConfig_BeanDependencyTest() {
        AnnotationConfigApplicationContext annotationConfigApplicationContext =
                new AnnotationConfigApplicationContext();
    
        annotationConfigApplicationContext.register(AppConfig_BeanDependency.class);
        annotationConfigApplicationContext.refresh();
    
        annotationConfigApplicationContext.close();
    }
    
    public static void main(String[] args) {
    
        AppConfig_BeanDependencyTest();
    }
    

    2.5 输出

    1. @Configuration开启时:

    use myschool default constructor!
    com.kikop.model.MySchool@701fc37a

    1. @Configuration关闭时(注意:MySchool被构造了两遍):

    use myschool default constructor!
    com.kikop.model.MySchool@631330c
    use myschool default constructor!
    com.kikop.model.MySchool@42f93a98

    3 @Configuration源码解读

    3.1总结

    Spring 容器在初始化刷新时,检查是否有@Configuration配置的注解类,如果有,则进行配置类的代理增强ConfigurationClassEnchancer(默认CGLIB)。

    配置类中的methodBean方法由lite变为full。AppConfig的配置类转换成AppConfig@BySpringCGLIB,从而Spring中@Bean注解的Beam方法在调用时会被Enchancer动态代理拦截。具体代理时机在容器刷新:invokeBeanFactoryPostProcessors方法中。

    一句话,它的本质是动态代理!

    具体实现如下:

    @Override
    public void refresh() throws BeansException, IllegalStateException {
       synchronized (this.startupShutdownMonitor) {
          // Prepare this context for refreshing.
          prepareRefresh();
    
          // Tell the subclass to refresh the internal bean factory.
          ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
          // Prepare the bean factory for use in this context.
          prepareBeanFactory(beanFactory);
    
          try {
             // Allows post-processing of the bean factory in context subclasses.
             postProcessBeanFactory(beanFactory);
    
             // Invoke factory processors registered as beans in the context.
             invokeBeanFactoryPostProcessors(beanFactory);
    
    /**
     * Instantiate and invoke all registered BeanFactoryPostProcessor beans,
     * respecting explicit order if given.
     * <p>Must be called before singleton instantiation.
     */
    protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
       PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
    
    // org\springframework\context\annotation\ConfigurationClassPostProcessor.java
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
       int factoryId = System.identityHashCode(beanFactory);
       if (this.factoriesPostProcessed.contains(factoryId)) {
          throw new IllegalStateException(
                "postProcessBeanFactory already called on this post-processor against " + beanFactory);
       }
       this.factoriesPostProcessed.add(factoryId);
       if (!this.registriesPostProcessed.contains(factoryId)) {
          // BeanDefinitionRegistryPostProcessor hook apparently not supported...
          // Simply call processConfigurationClasses lazily at this point then.
          processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
       }
       // 在这里进行配置类的增强
       enhanceConfigurationClasses(beanFactory);
       beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
    }
    
    if (configBeanDefs.isEmpty()) {
       // nothing to enhance -> return immediately
       return;
    }
    
    ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
    for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
       AbstractBeanDefinition beanDef = entry.getValue();
       // If a @Configuration class gets proxied, always proxy the target class
       beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
       try {
          // Set enhanced subclass of the user-specified bean class
          Class<?> configClass = beanDef.resolveBeanClass(this.beanClassLoader);
          if (configClass != null) {
             Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
    
    /**
     * Creates a new CGLIB {@link Enhancer} instance.
     */
    private Enhancer newEnhancer(Class<?> superclass, @Nullable ClassLoader classLoader) {
       Enhancer enhancer = new Enhancer();
       enhancer.setSuperclass(superclass);
       enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});
       enhancer.setUseFactory(false);
       enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
       enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
       enhancer.setCallbackFilter(CALLBACK_FILTER);
       enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
       return enhancer;
    }
    

    参考

    1.Spring官网

    https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-java-basic-concepts

    相关文章

      网友评论

          本文标题:2021-02-25_Spring源码学习笔记@Configur

          本文链接:https://www.haomeiwen.com/subject/bflyfltx.html