zoukankan      html  css  js  c++  java
  • springboot ---> spring ioc 注册流程 源码解析 this.prepareContext 部分

               现在都是在springboot 中 集成 spirng,那我们就从springboot 开始。

               一:springboot 启动main 函数

     public static void main(String[] args) throws Exception {
            SpringApplication.run(AuditCenterWebApp.class, args);
     }

      

      二:跟踪下来,会进入到springAppliaction  的 run(String... args) 方法。

     public ConfigurableApplicationContext run(String... args) {
            StopWatch stopWatch = new StopWatch();
            stopWatch.start();
            ConfigurableApplicationContext context = null;
            Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
            this.configureHeadlessProperty();
            SpringApplicationRunListeners listeners = this.getRunListeners(args);
            listeners.starting();
    
            Collection exceptionReporters;
            try {
                ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
          // 组织环境
                ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
                this.configureIgnoreBeanInfo(environment);
          // 打印我们设置的banner
                Banner printedBanner = this.printBanner(environment);
                /**创建applicationContext 默认webApplicationType 是 SERVLET,
    所以返回的是org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext对象
    */ context = this.createApplicationContext(); exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context); // 准备上下文 this.prepareContext(context, environment, listeners, applicationArguments, printedBanner); // 刷新上下文 this.refreshContext(context); this.afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch); } listeners.started(context); this.callRunners(context, applicationArguments); } catch (Throwable var10) { this.handleRunFailure(context, var10, exceptionReporters, listeners); throw new IllegalStateException(var10); } try { listeners.running(context); return context; } catch (Throwable var9) { this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null); throw new IllegalStateException(var9); } }

               

      三:准备上下文 this.prepareContext 

    点击进入,跟踪 this.load(context, sources.toArray(new Object[0])); 方法

        private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
            context.setEnvironment(environment);
            this.postProcessApplicationContext(context);
            this.applyInitializers(context);
            listeners.contextPrepared(context);
            if (this.logStartupInfo) {
                this.logStartupInfo(context.getParent() == null);
                this.logStartupProfileInfo(context);
            }
    
            context.getBeanFactory().registerSingleton("springApplicationArguments", applicationArguments);
            if (printedBanner != null) {
                context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
            }
    
            Set<Object> sources = this.getAllSources();
            Assert.notEmpty(sources, "Sources must not be empty");
            this.load(context, sources.toArray(new Object[0]));
            listeners.contextLoaded(context);
        }

      

      四:我们看一下 BeanDefinitionLoader 是如何创建的

    protected void load(ApplicationContext context, Object[] sources) {
            if (logger.isDebugEnabled()) {
                logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
            }
    
            BeanDefinitionLoader loader = this.createBeanDefinitionLoader(this.getBeanDefinitionRegistry(context), sources);
            if (this.beanNameGenerator != null) {
                loader.setBeanNameGenerator(this.beanNameGenerator);
            }
    
            if (this.resourceLoader != null) {
                loader.setResourceLoader(this.resourceLoader);
            }
    
            if (this.environment != null) {
                loader.setEnvironment(this.environment);
            }
    
            loader.load();
        }

                 

      (1)getBeanDefinitionRegistry,返回的是 BeanDefinitionRegistry 接口。 将 beanDefinitionRegistry 作为参数 创建 BeanDefinitionLoader

    BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
            Assert.notNull(registry, "Registry must not be null");
            Assert.notEmpty(sources, "Sources must not be empty");
        // 此处的source 就是第一步中 SpringApplication.run(AuditCenterWebApp.class,args) 中的 AuditCenterWebApp.class
    this.sources = sources;
        // new 一个注解的读取器
    this.annotatedReader = new AnnotatedBeanDefinitionReader(registry); this.xmlReader = new XmlBeanDefinitionReader(registry); if (this.isGroovyPresent()) { this.groovyReader = new GroovyBeanDefinitionReader(registry); } // new Bean定义的扫描器 this.scanner = new ClassPathBeanDefinitionScanner(registry); this.scanner.addExcludeFilter(new BeanDefinitionLoader.ClassExcludeFilter(sources)); }

      

      (2)我们看下AnnotatedBeanDefinitionReader 的创建,AnnotatedBeanDefinitionReader 里注册了 proccess。跟踪代码到 AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);

    在这个方法里 springboot 注册 了spring 的几个注解 processor, spring的注解分为几类,每一类注解都有相应注解处理器

    // configuration 注解,是个引导注解,所以的他的优先级是很高的,@Configuration 就是由他来处理
    org.springframework.context.annotation.internalConfigurationAnnotationProcessor -> org.springframework.context.annotation.ConfigurationClassPostProcessor
    // 自动装配的处理器,可以自动装配带注解的字段,他支持(@Value, @Autowired, @Inject, @Lookup),默认他的require=true
    org.springframework.context.annotation.internalAutowiredAnnotationProcessor -> org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
    // 用来检查java 的bean 的属性值 @Required
    org.springframework.context.annotation.internalRequiredAnnotationProcessor -> org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor
    // 这个注解支持许多java注解和jsr-250 注解。@PostConstruct,@PreDestroy,@Resource等
    org.springframework.context.annotation.internalCommonAnnotationProcessor -> org.springframework.context.annotation.CommonAnnotationBeanPostProcessor
    
    org.springframework.context.event.internalEventListenerProcessor -> org.springframework.context.event.EventListenerMethodProcessor
    org.springframework.context.event.internalEventListenerFactory -> org.springframework.context.event.DefaultEventListenerFactory

      五:好了回到第四步,调用了 BeanDefinitionLoader 的load()方法。再次跟进load()

    public int load() {
            int count = 0;
    // 此处source 是 AuditCenterWebApp
            Object[] var2 = this.sources;
            int var3 = var2.length;
    
            for(int var4 = 0; var4 < var3; ++var4) {
                Object source = var2[var4];
    // 将 AuditCenterWebApp 作为入参传入
                count += this.load(source);
            }
    
            return count;
        }

      六:这里判断启动类上是否有启动的注解

     private int load(Class<?> source) {
            if (this.isGroovyPresent() && BeanDefinitionLoader.GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
                BeanDefinitionLoader.GroovyBeanDefinitionSource loader = (BeanDefinitionLoader.GroovyBeanDefinitionSource)BeanUtils.instantiateClass(source, BeanDefinitionLoader.GroovyBeanDefinitionSource.class);
                this.load(loader);
            }
                // 是否是组件,会根据启动类中是否有启动的注解 或者 根据类的信息本身(类名,构造方法等)
            if (this.isComponent(source)) {
                this.annotatedReader.register(new Class[]{source});
                return 1;
            } else {
                return 0;
            }
        }

      一直往下跟踪,跟踪到 org.springframework.context.annotation.AnnotatedBeanDefinitionReader#doRegisterBean 方法

           这个方法叫doRegisterBean  ,根据类型和方法名 可以知道:这个方法是注册 注解处理器的bean定义信息的

     <T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name, @Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
        // 创建bean的定义信息对象(类名,类的元数据对象) AnnotatedGenericBeanDefinition abd
    = new AnnotatedGenericBeanDefinition(annotatedClass); if (!this.conditionEvaluator.shouldSkip(abd.getMetadata())) { abd.setInstanceSupplier(instanceSupplier); ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd); // singleton abd.setScope(scopeMetadata.getScopeName()); // auditCenterWebApp String beanName = name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry); AnnotationConfigUtils.processCommonDefinitionAnnotations(abd); int var10; int var11; // qualifiers == null 上一层写死 if (qualifiers != null) { Class[] var9 = qualifiers; var10 = qualifiers.length; for(var11 = 0; var11 < var10; ++var11) { Class<? extends Annotation> qualifier = var9[var11]; if (Primary.class == qualifier) { abd.setPrimary(true); } else if (Lazy.class == qualifier) { abd.setLazyInit(true); } else { abd.addQualifier(new AutowireCandidateQualifier(qualifier)); } } } BeanDefinitionCustomizer[] var13 = definitionCustomizers; var10 = definitionCustomizers.length; for(var11 = 0; var11 < var10; ++var11) { BeanDefinitionCustomizer customizer = var13[var11]; customizer.customize(abd); } // 将beanDefinition 和 beanName 包装成BeanDefinitionHolder, adb就是bean定义信息对象 BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry); } }

       跟踪 BeanDefinitionReaderUtils.registerBeanDefinition 方法。

             GenericApplicationContext 类中 定义的beanFactory是 DefaultListableBeanFactory,所以最后调的是 DefaultListableBeanFactory 的 registerBeanDefinition

      public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
            String beanName = definitionHolder.getBeanName();
            // 调用的是 GenericApplicationContext 的registerBeanDefinition 方法。
            registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
            String[] aliases = definitionHolder.getAliases();
            if (aliases != null) {
                String[] var4 = aliases;
                int var5 = aliases.length;
    
                for(int var6 = 0; var6 < var5; ++var6) {
                    String alias = var4[var6];
                    registry.registerAlias(beanName, alias);
                }
            }
    
        }

          这里是开始注册bean 定义信息(注解处理器,启动类 等 基础bean信息),将bean信息注册到 

    List<String> beanDefinitionNames                                         // bean 定义信息的注册名称 列表,有序
    Map<String, BeanDefinition> beanDefinitionMap                  // bean 定义信息 的映射,无序
    Set<String> manualSingletonNames                                     //手动注册的单例名称列表

     public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
            Assert.hasText(beanName, "Bean name must not be empty");
            Assert.notNull(beanDefinition, "BeanDefinition must not be null");
            if (beanDefinition instanceof AbstractBeanDefinition) {
                try {
                    ((AbstractBeanDefinition)beanDefinition).validate();
                } catch (BeanDefinitionValidationException var9) {
                    throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", var9);
                }
            }
            //Map<String, BeanDefinition> beanDefinitionMap ,key=bean名称,bean 对象的定义
            // bean 定义对象的映射,beanName 是对象的全限定名称
            BeanDefinition oldBeanDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName);
            if (oldBeanDefinition != null) {
            // 如果定义了重复的bean 名称,是否允许覆盖,默认true
                if (!this.isAllowBeanDefinitionOverriding()) {
                    throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + "': There is already [" + oldBeanDefinition + "] bound.");
                }
    
                if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
                    if (this.logger.isWarnEnabled()) {
                        this.logger.warn("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
                    }
                } else if (!beanDefinition.equals(oldBeanDefinition)) {
                    if (this.logger.isInfoEnabled()) {
                        this.logger.info("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
                    }
                } else if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
                }
    
                this.beanDefinitionMap.put(beanName, beanDefinition);
            } else {
            // 注册工作是否已经启动
                if (this.hasBeanCreationStarted()) {
                    synchronized(this.beanDefinitionMap) {
                        this.beanDefinitionMap.put(beanName, beanDefinition);
                        List<String> updatedDefinitions = new ArrayList(this.beanDefinitionNames.size() + 1);
                        updatedDefinitions.addAll(this.beanDefinitionNames);
                        updatedDefinitions.add(beanName);
                        this.beanDefinitionNames = updatedDefinitions;
                        if (this.manualSingletonNames.contains(beanName)) {
                            Set<String> updatedSingletons = new LinkedHashSet(this.manualSingletonNames);
                            updatedSingletons.remove(beanName);
                            this.manualSingletonNames = updatedSingletons;
                        }
                    }
                } else {
                // 正常的话,会走到这里。设置bean 的名称和定义
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    // bean定义的名称列表
                    this.beanDefinitionNames.add(beanName);
                    this.manualSingletonNames.remove(beanName);
                }
    
                this.frozenBeanDefinitionNames = null;
            }
    
            if (oldBeanDefinition != null || this.containsSingleton(beanName)) {
                this.resetBeanDefinition(beanName);
            }
    
        }

    ok,总结下  this.prepareContext  主要做的事情

     环境预处理

    创建系统上下文

    打印banner

    预加载,注册 基础bean定义 (注解处理器,启动类,bean名称处理器 等)

    设置上下文监听

     
  • 相关阅读:
    【CTF WEB】函数绕过
    【CTF WEB】命令执行
    【CTF WEB】文件包含
    【CTF WEB】GCTF-2017读文件
    【技巧总结】Penetration Test Engineer[5]-Operating System Security(SQL Server、MySQL提权)
    【技巧总结】Penetration Test Engineer[4]-Web-Security(文件处理、会话管理、访问控制、SSRF、反序列化漏洞)
    【技巧总结】Penetration Test Engineer[3]-Web-Security(SQL注入、XXS、代码注入、命令执行、变量覆盖、XSS)
    【技巧总结】Penetration Test Engineer[2]-Information gathering
    【技巧总结】Penetration Test Engineer[1]-Basic
    【 Linux 】单台服务器上并发TCP连接数
  • 原文地址:https://www.cnblogs.com/zhangXingSheng/p/11310635.html
Copyright © 2011-2022 走看看