Spring之ClassPathXmlApplicationContext(refresh未更新完)

Spring之ClassPathXmlApplicationContext

划重点 : 所有方法,直接复制查字典,即可明白其方法发作用

  1. PropertySource:属性源。key-value 属性对抽象,用于配置数据。

  2. PropertyResolver:属性解析器。用于解析属性配置。

  3. Profile:剖面。只有被激活的Profile才会将其中所对应的Bean注册到Spring容器中

  4. Environment:环境。Profile 和 PropertyResolver 的组合。

继承实现体系如下
在这里插入图片描述

简单示例,供原码解析使用(通过配置文件将java类加载到spring中)

配置文件context.xml

<?xml version="1.0" encoding="UTF-8"?>    
<beans>    
    <bean class="base.SimpleBean"></bean>
</beans>

java类 SimpleBean

public class SimpleBean {
    public void send() {
        System.out.println("I am send method from SimpleBean!");
    }
}

启动代码 main() 方法

public static void main(String[] args) {
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("config.xml");
    SimpleBean bean = context.getBean(SimpleBean.class);
    bean.send();
    context.close();
}

代码1 – > ClassPathXmlApplicationContext类构造方法

public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
        this(new String[]{configLocation}, true, (ApplicationContext)null);
}
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext 										parent) throws BeansException {
        super(parent); // 传递的是null,所以暂时不考虑这里 -->代码2
        this.setConfigLocations(configLocations); //保存配置 --> 代码3
        if (refresh) {//默认为true
            this.refresh();//初始化容器 -->代码4
        }

}

代码2 --> 一直点击super(parent),沿着继承体系,看其父构造器代码 , 追根溯源找到AbstractApplicationContext抽象类,其构造方法如下(此处占时到这里,因为parant传递的是null,此处暂时不考虑,日后再补充)

public AbstractApplicationContext(ApplicationContext parent) {
        this();
        this.setParent(parent);
}
//点击this() 找到 无参构造方法
public AbstractApplicationContext() {
        this.logger = LogFactory.getLog(this.getClass());
        this.id = ObjectUtils.identityToString(this);
        this.displayName = ObjectUtils.identityToString(this);
        this.beanFactoryPostProcessors = new ArrayList();
        this.active = new AtomicBoolean();
        this.closed = new AtomicBoolean();
        this.startupShutdownMonitor = new Object();
        this.applicationListeners = new LinkedHashSet();
        this.resourcePatternResolver = this.getResourcePatternResolver();
}
//setParent(parent)方法 ()
public void setParent(ApplicationContext parent) {
        this.parent = parent;
        if (parent != null) {
            Environment parentEnvironment = parent.getEnvironment();
            if (parentEnvironment instanceof ConfigurableEnvironment) {
                this.getEnvironment().merge((ConfigurableEnvironment)parentEnvironment);
            }
        }

}

代码 – > 3 this.setConfigLocations(configLocations)保存配置方法,即存xml的方法,代码如下

//这里记住将xml存储到了configLocations
public void setConfigLocations(@Nullable String... locations) {
        if (locations != null) {
            Assert.noNullElements(locations, "Config locations must not be null"); //这里使用的是断言来判断是否有空元素,有的话会直接抛出异常
            this.configLocations = new String[locations.length]; 

            for(int i = 0; i < locations.length; ++i) {
                //存储xml到configLocations数组中 resolvePath()方法 --> 代码3.1 
                this.configLocations[i] = this.resolvePath(locations[i]).trim();
            }
        } else {
            this.configLocations = null;
        }

 }

代码–>3.1 占位符解析和替换 resolvePath(path)

1. //占位符解析和替换
protected String resolvePath(String path) {
    // 从环境中解析path中的占位符 (getEnviroment()即为获取环境,resolveRequiredPlaceholders()分解必要的占位符,打开有道词典翻译即可获取字面解释)
    return this.getEnvironment().resolveRequiredPlaceholders(path);
}

代码–>3.11 getEnvironment()环境变量属性配置

2. // 配置环境变量,很简单,有就返回,没有就创建一个环境
public ConfigurableEnvironment getEnvironment() {
    if (this.environment == null) {
        this.environment = this.createEnvironment();
    }

    return this.environment;
}
3. //创建环境方法,即新建StandardEnvironment()
protected ConfigurableEnvironment createEnvironment() {
    return new StandardEnvironment();
}
4. //在StandardEnvironment中有一个无参构造方法,同时它继承了AbstractEnvironment抽象类,AbstractEnvironment里面的无参构造方法又调用了customizePropertySources()方法
public AbstractEnvironment() {
    this.propertyResolver = new PropertySourcesPropertyResolver(this.propertySources);
    this.customizePropertySources(this.propertySources);
}
5. //而在StandardEnvironment类中又重写了customizePropertySources()方法,则初始化类的时候,该方法是被调用的 , 这里是配置属性,环境的操作的操作
protected void customizePropertySources(MutablePropertySources propertySources) {
    propertySources.addLast(new PropertiesPropertySource("systemProperties", this.getSystemProperties()));
    propertySources.addLast(new SystemEnvironmentPropertySource("systemEnvironment", this.getSystemEnvironment()));
}
6. //getSystemProperties()方法
public Map<String, Object> getSystemProperties() {
    try {
        //获取当前系统的属性 可以自己debug走一下看看,包括版本,java信息等等共54个
        return System.getProperties();
    } catch (AccessControlException var2) {
        return new ReadOnlySystemAttributesMap() {
            @Nullable
            protected String getSystemAttribute(String attributeName) {
                try {
                    //如果获取全部属性失败,则获取单个指定属性
            //如果获取单个还是不行则抛出异常
                    return System.getProperty(attributeName);
                } catch (AccessControlException var3) {
                    if (AbstractEnvironment.this.logger.isInfoEnabled()) {
                        AbstractEnvironment.this.logger.info("Caught AccessControlException when accessing system property '" + attributeName + "'; its value will be returned [null]. Reason: " + var3.getMessage());
                    }

                    return null;
                }
            }
        };
    }
}

7. //getSystemEnvironment()方法
    public Map<String, Object> getSystemEnvironment() {
        if (this.suppressGetenvAccess()) {
            return Collections.emptyMap();
        } else {
            try {
                //获取当前系统环境变量,就是我们在电脑->属性->环境变量配置的东西
                return System.getenv();
            } catch (AccessControlException var2) {
                return new ReadOnlySystemAttributesMap() {
                    @Nullable
                    protected String getSystemAttribute(String attributeName) {
                        try {
                            //如果获取全部环境变量失败,则获取单个指定变量
            		//如果获取单个还是不行则抛出异常
                            return System.getenv(attributeName);
                        } catch (AccessControlException var3) {
                            if (AbstractEnvironment.this.logger.isInfoEnabled()) {
                                AbstractEnvironment.this.logger.info("Caught AccessControlException when accessing system environment variable '" + attributeName + "'; its value will be returned [null]. Reason: " + var3.getMessage());
                            }

                            return null;
                        }
                    }
                };
            }
        }
    }

代码–>3.12 resolveRequiredPlaceholders()解析path

2. // resolveRequiredPlaceholders()方法
	public String resolveRequiredPlaceholders(String text) throws 					                                                       IllegalArgumentException {
        return this.propertyResolver.resolveRequiredPlaceholders(text);
    }

3. //跟踪代码 找到 AbstractPropertyResolver 类下的resolveRequiredPlaceholders()方法
   //为什么找这个类下的该方法,,因为本类在无参构造方法的时候 有以下代码
    public AbstractEnvironment() {
    //this.propertyResolver 等于 创建的PropertySourcesPropertyResolver类,而PropertySourcesPropertyResolver类继承的是AbstractPropertyResolver类
        this.propertyResolver = new                          PropertySourcesPropertyResolver(this.propertySources);
    //下面的方法在 代码3.11解释了
        this.customizePropertySources(this.propertySources);
    }

4. //resolveRequiredPlaceholders()的实现
    public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
    //strictHelper 是 PropertyPlaceholderHelper 对象,如果为空就创建一个
        if (this.strictHelper == null) {
            this.strictHelper = this.createPlaceholderHelper(false);
        }
	//开始解析占位符
        return this.doResolvePlaceholders(text, this.strictHelper);
    }

5. //createPlaceholderHelper()方法
    private PropertyPlaceholderHelper createPlaceholderHelper(boolean            		                                 ignoreUnresolvablePlaceholders) {
    //其中  this.placeholderPrefix =  "${"
    //this.placeholderSuffix = "}"    
    //this.valueSeparator = ":"
    //ignoreUnresolvablePlaceholders = false  以上均为定义的常量
        return new PropertyPlaceholderHelper(this.placeholderPrefix,  	    			this.placeholderSuffix, this.valueSeparator, ignoreUnresolvablePlaceholders);
    }

6. // 返回上一级 doResolvePlaceholders()方法
    private String doResolvePlaceholders(String text, PropertyPlaceholderHelper helper) {
    //helper 刚刚创建的包含特殊字符${}的类
    //this :: function jdk1.8的新特性,,引用该方法 -- getPropertyAsRawString 见代码3.13
        return helper.replacePlaceholders(text, this::getPropertyAsRawString);
	}
7. // replacePlaceholders()方法
    public String replacePlaceholders(String value, PropertyPlaceholderHelper.PlaceholderResolver placeholderResolver) {
        Assert.notNull(value, "'value' must not be null");
        return this.parseStringValue(value, placeholderResolver, (Set)null);
    }
8. //继续调用 parseStringValue ()方法 ,进行占位符替换

 //this.placeholderPrefix: ${
 //this.placeholderSuffix: }
 //this.valueSeparator: :
protected String parseStringValue(String value, PropertyPlaceholderHelper.PlaceholderResolver placeholderResolver, @Nullable Set<String> visitedPlaceholders) {
    //获取 ${ 在路径中的位置,用于判断是否需要进行解析,如果没有就直接返回
        int startIndex = value.indexOf(this.placeholderPrefix);
        if (startIndex == -1) {
            return value;
        } else {
            StringBuilder result = new StringBuilder(value);

            while(startIndex != -1) {
          
             //而是获取 "}" 的位置 有兴趣可以自己走一下代码,这个方法发目的就是取到 } 的位置
                int endIndex = this.findPlaceholderEndIndex(result, startIndex);
                if (endIndex != -1) {
                    //获取占位符 即${} 中的部分
                    String placeholder = result.substring(startIndex + this.placeholderPrefix.length(), endIndex);
                    String originalPlaceholder = placeholder;
                    if (visitedPlaceholders == null) { //如果visitedPlaceholders为空,创建一个HashSet(4)
                        visitedPlaceholders = new HashSet(4);
                    }
					//然后把我们刚刚取到的placeholder放到里面,放入失败则抛异常
                    if (!((Set)visitedPlaceholders).add(placeholder)) {
                        throw new IllegalArgumentException("Circular placeholder reference '" + placeholder + "' in property definitions");
                    }
					//递归调用了一次 再次检查里面有没有包含的内容
                    placeholder = this.parseStringValue(placeholder, placeholderResolver, (Set)visitedPlaceholders);
                    //此处比较饶,我也没有很好的理解,简单说就是使用函数式接口@FunctionalInterface 调用了上面传递进来的方法 : this::getPropertyAsRawString()这个方法简单说就是从之前的说的初始化环境时,放到里面的spring属性对应的value值
                    String propVal = placeholderResolver.resolvePlaceholder(placeholder); // --> context
                    if (propVal == null && this.valueSeparator != null) {
                        int separatorIndex = placeholder.indexOf(this.valueSeparator);
                        if (separatorIndex != -1) {
                            String actualPlaceholder = placeholder.substring(0, separatorIndex);
                            String defaultValue = placeholder.substring(separatorIndex + this.valueSeparator.length());
                            propVal = placeholderResolver.resolvePlaceholder(actualPlaceholder);
                            if (propVal == null) {
                                propVal = defaultValue;
                            }
                        }
                    }

                    if (propVal != null) {
                        propVal = this.parseStringValue(propVal, placeholderResolver, (Set)visitedPlaceholders);
                        //将获取到的值进行替换,得到的就是配置文件真实名称
                        result.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal);
                        if (logger.isTraceEnabled()) {
                            logger.trace("Resolved placeholder '" + placeholder + "'");
                        }

                        startIndex = result.indexOf(this.placeholderPrefix, startIndex + propVal.length());
                    } else {
                        if (!this.ignoreUnresolvablePlaceholders) {
                            throw new IllegalArgumentException("Could not resolve placeholder '" + placeholder + "' in value \"" + value + "\"");
                        }

                        startIndex = result.indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.length());
                    }

                    ((Set)visitedPlaceholders).remove(originalPlaceholder);
                } else {
                    startIndex = -1;
                }
            }

            return result.toString();
        }
    }

到此,解析路径就结束了

附 : 代码 --> 3.13 getPropertyAsRawString()

protected <T> T getProperty(String key, Class<T> targetValueType, boolean   	    	         resolveNestedPlaceholders) {
        if (this.propertySources != null) {
            Iterator var4 = this.propertySources.iterator();

            while(var4.hasNext()) {
                PropertySource<?> propertySource = (PropertySource)var4.next();
                if (this.logger.isTraceEnabled()) {
                    this.logger.trace("Searching for key '" + key + "' in PropertySource '" + propertySource.getName() + "'");
                }
			//根据key 取值 ,此处即根据key 为 spring 取 对应的value
                Object value = propertySource.getProperty(key);
                if (value != null) {
                    if (resolveNestedPlaceholders && value instanceof String) {
                        value = this.resolveNestedPlaceholders((String)value);
                    }

                    this.logKeyFound(key, propertySource, value);
                    return this.convertValueIfNecessary(value, targetValueType);
                }
            }
        }

        if (this.logger.isTraceEnabled()) {
            this.logger.trace("Could not find key '" + key + "' in any property source");
        }

        return null;
    }

代码 --> 4 refresh() 核心代码

public void refresh() throws BeansException, IllegalStateException {
        Object var1 = this.startupShutdownMonitor;
        synchronized(this.startupShutdownMonitor) {
            // 准备上下文,记录容器的启动时间startupDate, 标记容器为激活,初始化上下文环境如文件路径信息,验证必填属性是否填写 --> 代码4.1
            this.prepareRefresh();
            // 这步比较重要(解析),告诉子类去刷新bean工厂,这步完成后配置文件就解析成一个个bean定义,注册到BeanFactory(但是未被初始化,仅将信息写到了beanDefination的map中) -->代码4.2
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            // 设置beanFactory类加载器,准备bean工厂 -->代码4.3
            this.prepareBeanFactory(beanFactory);

            try {
                 // 允许子类上下文中对beanFactory做后期处理
                postProcessBeanFactory(beanFactory);
                // 调用BeanFactoryPostProcessor各个实现类的方法
                invokeBeanFactoryPostProcessors(beanFactory);
                // 注册 BeanPostProcessor 的实现类,注意看和 BeanFactoryPostProcessor 的区别
                // 此接口两个方法: postProcessBeforeInitialization和postProcessAfterInitialization
                // 两个方法分别在 Bean 初始化之前和初始化之后得到执行。注意,到这里 Bean 还没初始化
                registerBeanPostProcessors(beanFactory);
                //初始化ApplicationContext的MessageSource
                initMessageSource();
                //初始化ApplicationContext事件广播器
                initApplicationEventMulticaster();
                // 初始化子类特殊bean(钩子方法)
                onRefresh();
                // 注册事件监听器
                registerListeners();
                // 初始化所有singleton bean  重点!!重点!!
                finishBeanFactoryInitialization(beanFactory);
                // 广播事件,ApplicationContext初始化完成
                finishRefresh();
            } catch (BeansException var9) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
                }

                this.destroyBeans();
                this.cancelRefresh(var9);
                throw var9;
            } finally {
                this.resetCommonCaches();
            }

        }
    }

代码–>4.1this.prepareRefresh()方法代码流程

1. //prepareRefresh()方法
protected void prepareRefresh() {
    	// 启动时间
        this.startupDate = System.currentTimeMillis();
        //这里使用了AtomicBoolean类,这个类的作用是能够保证在高并发的情况下只有一个线程能够访问这个属性值 类似于boolean 不过boolean在多线程下是不安全的 ,这里的意思是 ,
        //是否关闭,否
    	this.closed.set(false);
        //是否开启,是
    	this.active.set(true);
        if (this.logger.isDebugEnabled()) {
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Refreshing " + this);
            } else {
                this.logger.debug("Refreshing " + this.getDisplayName());
            }
        }
//初始化Property,这个方法在本类中是空方法,许多文档都说这里是调用了他的实现类的方法,但是我用debug没有看到他进入自己的实现类,而且也没有地方可以表示他进入了实现类,所以此处我认为就是一个空方法
        this.initPropertySources();
        //getEnvironment()之前有说过,见代码3.11
       //validateRequiredProperties()方法,主要为空检验,确保环境为空
        this.getEnvironment().validateRequiredProperties();
        if (this.earlyApplicationListeners == null) {
            this.earlyApplicationListeners = new LinkedHashSet(this.applicationListeners);
        } else {
            this.applicationListeners.clear();
            this.applicationListeners.addAll(this.earlyApplicationListeners);
        }
		//创建一个set
        this.earlyApplicationEvents = new LinkedHashSet();
    }
2.//validateRequiredProperties()方法有两个实现类,此处取自,AbstractPropertyResolver类(也是我们解析${}的类,为什么取这个在上一次调用这个类时有讲解,见代码3.12)
public void validateRequiredProperties() {
        MissingRequiredPropertiesException ex = new MissingRequiredPropertiesException();//一个异常类
        Iterator var2 = this.requiredProperties.iterator();//取配置值
        while(var2.hasNext()) {
            String key = (String)var2.next();
            if (this.getProperty(key) == null) { // 等于null ,则在异常中添加key
                ex.addMissingRequiredProperty(key);
            }
        }

        if (!ex.getMissingRequiredProperties().isEmpty()) {//不为空,则抛出异常
            throw ex;
        }
    }

代码 --> 4.2 this.obtainFreshBeanFactory() 按照步骤一步一步看, 寻找configLocations数据

// 1. 点开
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        this.refreshBeanFactory();
        return this.getBeanFactory();
}
//2.ctrl+T找到他的抽象继承类AbstractRefreshableApplicationContext里面的refreshBeanFactory类
protected final void refreshBeanFactory() throws BeansException {
        if (this.hasBeanFactory()) {//关闭旧的beanFactory
            this.destroyBeans();//销毁所有的bean
            this.closeBeanFactory();//关闭bean工厂
        }

        try {//创建新的beanFactory(创建的是DefaultListableBeanFactory)
            DefaultListableBeanFactory beanFactory = this.createBeanFactory();
            //然后重新设置在closeBeanFactory()置为null的serialzationId
            beanFactory.setSerializationId(this.getId());
            //自定义beanFactory,设置是否允许覆盖、是否循环引用标识
            this.customizeBeanFactory(beanFactory);
            
            this.loadBeanDefinitions(beanFactory);
            Object var2 = this.beanFactoryMonitor;
            synchronized(this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        } catch (IOException var5) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5);
        }
    }
//3.点击this.loadBeanDefinitions(beanFactory);从抽象类XmlWebApplicationContext取该方法
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        beanDefinitionReader.setResourceLoader(this);
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
        this.initBeanDefinitionReader(beanDefinitionReader);
        this.loadBeanDefinitions(beanDefinitionReader);
    }
//4.点击this.loadBeanDefinitions(beanDefinitionReader); 
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
        String[] configLocations = this.getConfigLocations();
        if (configLocations != null) {
            String[] var3 = configLocations;
            int var4 = configLocations.length;

            for(int var5 = 0; var5 < var4; ++var5) {
                String configLocation = var3[var5];
                reader.loadBeanDefinitions(configLocation);
            }
        }

  }
//5.找到了this.getConfigLocations(),找到super.getConfigLocations();
public String[] getConfigLocations() {
        return super.getConfigLocations();
 }
//点击super.getConfigLocations() 找到 AbstractRefreshableConfigApplicationContext抽象类的getConfigLocations()方法,即获取的是我们在  代码 -->3执行setConfigLocations()存放的数据 
protected String[] getConfigLocations() {
        return this.configLocations != null ? this.configLocations:this.getDefaultConfigLocations();
}

代码–>4.3prepareBeanFactory(beanFactory)准备bean工厂

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    //设置类加载器:存在则直接设置/不存在则新建一个默认类加载器
        beanFactory.setBeanClassLoader(this.getClassLoader());
    //设置EL表达式解析器(Bean初始化完成后填充属性时会用到)
        beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
     //设置属性注册解析器PropertyEditor
        beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, this.getEnvironment()));
    // 将当前的ApplicationContext对象交给ApplicationContextAwareProcessor类来处理,从而在Aware接口实现类中的注入applicationContext
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
    //设置忽略自动装配的接口
        beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
        beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
        beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
        beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
    //注册可以解析的自动装配
        beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
        beanFactory.registerResolvableDependency(ResourceLoader.class, this);
        beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
        beanFactory.registerResolvableDependency(ApplicationContext.class, this);
        beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
    //如果当前BeanFactory包含loadTimeWeaver Bean,说明存在类加载期织入AspectJ,则把当前BeanFactory交给类加载期BeanPostProcessor实现类LoadTimeWeaverAwareProcessor来处理,从而实现类加载期织入AspectJ的目的。
        if (beanFactory.containsBean("loadTimeWeaver")) {
            beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
            beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
        }
//注册当前容器环境environment组件Bean
        if (!beanFactory.containsLocalBean("environment")) {
            beanFactory.registerSingleton("environment", this.getEnvironment());
        }
//注册系统配置systemProperties组件Bean
        if (!beanFactory.containsLocalBean("systemProperties")) {
            beanFactory.registerSingleton("systemProperties", this.getEnvironment().getSystemProperties());
        }
//注册系统环境systemEnvironment组件Bean
        if (!beanFactory.containsLocalBean("systemEnvironment")) {
            beanFactory.registerSingleton("systemEnvironment", this.getEnvironment().getSystemEnvironment());
        }

}




sLocalBean("environment")) {
            beanFactory.registerSingleton("environment", this.getEnvironment());
        }
//注册系统配置systemProperties组件Bean
        if (!beanFactory.containsLocalBean("systemProperties")) {
            beanFactory.registerSingleton("systemProperties", this.getEnvironment().getSystemProperties());
        }
//注册系统环境systemEnvironment组件Bean
        if (!beanFactory.containsLocalBean("systemEnvironment")) {
            beanFactory.registerSingleton("systemEnvironment", this.getEnvironment().getSystemEnvironment());
        }

}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值