Spring的IoC容器是一个提供IoC支持的轻量级容器,IoC容器为管理对象之间的依赖关系提供了基础功能。Spring为我们提供了两种容器:BeanFactory和ApplicationContext。在基于Spring的JavaEE应用中,所有的组件都被当成Bean处理,包括数据源、Hibernate的SessionFactory。

应用中所有组件都处于Spring的管理下,都被Spring以Bean的方式管理,Spring负责创建Bean实例,并管理其生命周期。Spring里的Bean是非常广义的概念,任何的Java对象、Java组件都被当成Bean处理。对于Spring而言,一切Java对象都是Bean。

Bean在Spring容器中运行,无须感受Spring容器的存在,一样可以接受Spring的依赖注入,包括Bean成员变量的注入、协作者的注入、依赖关系的注入等。

Java程序面向接口编程,无须关心Bean实例的实现类:但Spring容器负责创建Bean实例,因此必须精确知道每个Bean实例的实现类,故Spring配置文件必须制定Bean实例的实现类。​​​​​​

Spring容器最基本的接口就是BeanFactory。BeanFactory负责配置、创建、管理Bean,它有一个子接口:ApplicationContext,因此也被称为Spring上下文。Spring还负责管理Bean与Bean之间的关系。

  • BeanFactory:是基础类型的IoC容器,提供完整的IoC服务支持。如果没有特殊指定,默认采用延 迟初始化策略。只有当客户端对象需要访问容器中的某个受管对象的时候,才对该受管对象进行初 始化以及依赖注入操作。所以,相对来说,容器启动初期速度较快,所需要的资源有限。对于资源 有限,并且功能要求不是很严格的场景,BeanFactory是比较合适的IoC容器选择。
  • ApplicationContext:它是在BeanFactory的基础上构建的,是相对比较高级的容器实现,除了拥 有BeanFactory的所有支持,ApplicationContext还提供了其他高级特性,比如事件发布、国际化 信息支持等。ApplicationContext所管理的对象,在该类型容器启动之后,默认全部初始化并绑定 完成。所以,相对于BeanFactory来说,ApplicationContext要求更多的系统资源,同时,因为在 启动时就完成所有初始化,容 器启动时间较之BeanFactory也会长一些。在那些系统资源充足,并且要求更多功能的场景中, ApplicationContext类型的容器是比较合适的选择。

最大的区别:BeanFactory与ApplicationContext实例化容器的Bean的时机不同:前者等到程序需要Bean实例时才创建Bean;而后者在容器创建ApplicationContext实例时,同时创建容器中所有singleton作用域的Bean,因此可能需要更多的系统开销。一旦创建成功,后面的响应速度更快,因此,对于普通的Java EE应用,推荐使用ApplicationContext作为Spring容器。创建BeanFactory时不会立即创建Bean实例,所以有可能程序可以正确地创建BeanFactory实例,但当请求Bean实例时依然抛出一个异常:创建Bean实例或注入它的依赖关系时出现错误。配置错误的延迟出现,会给系统引入不安全的因素。ApplicationContext但可以在容器初始化阶段就检验出配置错误。

1,BeanFactory

BeanFactory采用了工厂设计模式,即Bean容器模式,负责读取Bean的配置文件,管理对象的生成、加载,维护Bean对象与Bean对象之间的依赖关系,负责Bean的生命周期。对于简单的应用程序来说,使用BeanFactory就已经足够管理Bean,在对象的管理上就可以获得许多便利性。

BeanFactory接口包含如下几个基本方法:

方法 描述
boolean containsBean(String name) 判断Spring容器是否包含id为name的Bean实例
<T> T getBean(Class<T> requiredType) 获取Spring容器中属于requiredType类型的、惟一的Bean实例
Object getBean(String name) 返回容器id为name的Bean实例
<T> T getBean(String name.Class requiredType) 返回容器中id为name,并且类型为requiredType的Bean。
Class<?> getType(String name) 返回容器中id为name的Bean实例的类型

调用者只需要使用getBean()方法即可获得指定Bean的引用,无须关心Bean的实例化过程。Bean实例的创建、初始化以及依赖关系的注入都由Spring容器完成。

BeanFactory是整个Spring的重点所在,整个Spring的核心都围绕这BeanFactory。BeanFactory只是个接口,并不是IOC容器的具体实现,但是Spring容器给出了很多种实现,如 DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext等。

BeanFacotry是spring中比较原始的Factory。如DefaultListableBeanFactory就是一种典型的BeanFactory。原始的BeanFactory无法支持Spring的许多插件,如AOP功能、Web应用等。

创建Spring容器的实例时,必须提供Spring容器管理Bean的详细配置信息。Spring的配置信息通畅采用XML配置文件来设置。因此,创建BeanFactory实例时,应该提供XML配置文件作为参数。

XML配置文件通常使用Resource对象传入。Resource接口是Spring提供的资源访问接口,通过使用该接口,Spring能以简单、透明的方式访问磁盘、类路径以及网络上的资源。

//搜索类加载路径下的applicationContext.xml
Resource resource = new ClassPathResource("applicationContext.xml");
//创建默认的BeanFactory容器
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
//让默认的BeanFactory容器加载isr对应的XML文件
new XmlBeanDefinitionReader(beanFactory).loadBeanDefinitions(resource);
Person chinese = beanFactory.getBean("chinese",Person.class);

或者

//搜索类加载路径下的applicationContext.xml
Resource resource = new FileSystemResource("applicationContext.xml");

如果需要加载多个配置文件来创建Spring容器,则应该采用BeanFactory的子接口ApplicationContext来创建。

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Person chinese = context.getBean("chinese", Person.class);
chinese.useAxe();

或者

ApplicationContext context = new FileSystemXmlApplicationContext("applicationContext.xml");

2,ApplicationContext

ApplicationContext 面向使用 Spring 框架的开发者,几乎所有的应用场合(除非对于某些内存非常关键的应用)都直接使用 ApplicationContext 而非底层的 BeanFactory作为Spring容器,因此把Spring容器称为Spring上下文

ApplicationContext是BeanFactory接口的子接口增强了BeanFactory的功能。对于大部分Java EE应用而言,使用它作为Spring容器更方便,可以使用Spring所提供的一些特色及高级的功能:

  • ApplicationContext提供BeanFactory所有的功能
  • 提供了取得资源文件(Resource File)更方便的方法
  • 提供了文字消息解析的方法
  • 继承了MessageSource接口,因此支持国际化消息
  • 事件机制
  • 载入多个配置文件等

只有对某些内存非常关键的应用,才考了使用BeanFactory。

其常用实现类:FileSystemXmlApplicationContext、ClassPathXmlApplicationContext和AnnotationConfigApplicationContext(建议不用)。

当系统创建ApplicationContext容器时,默认会预初始化所有的singleton Bean。也就是说,当ApplicationContext容器初始化完成后,容器会自动初始化所有的singleton Bean,包括调用构造器创建时将有较大的系统开销,但一旦ApplicationContext初始化完成,程序后面获取singleton Bean实例时将拥有较好的性能。为了组织Spring预初始化容器中的singleton Bean,可以为<bean.../>元素指定lazy-init="true",该属性用于阻止容器预初始化该Bean。因此如果为上面的<bean.../>元素指定了lazy-init="true",那么即使使用ApplicationContext作为Spring容器,Spring也不会预初始化该singleton Bean。

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Chinese chinese = context.getBean("chinese", Chinese.class);
chinese.useAxe();

(1)FileSystemXmlApplicationContext可以指定XML的绝对或相对路径在读取Bean的定义文件;默认是去项目的路径下加载,可以是相对路径,也可以是绝对路径,若是绝对路径,“file:” 前缀可以缺省。

ApplicationContext factory=new FileSystemXmlApplicationContext("src/appcontext.xml"); //使用了  classpath:  前缀,作为标志,  这样,FileSystemXmlApplicationContext 也能够读入classpath下的相对路径
ApplicationContext factory=new FileSystemXmlApplicationContext("classpath:appcontext.xml");
ApplicationContext factory=new FileSystemXmlApplicationContext("file:G:/Test/src/appcontext.xml");
ApplicationContext factory=new FileSystemXmlApplicationContext("G:/Test/src/appcontext.xml");

(2)ClassPathXmlApplicationContext:从Classpath设定的路径中读取Bean的定义文件;默认会去 classPath 路径下找。classPath 路径指的就是编译后的 classes 目录;“classpath:” 是可以缺省的。如果是绝对路径,就需要加上 “file:” 前缀,不可缺省。

ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
ApplicationContext ac = new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml","dao.xml"});
ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:/*.xml");
ApplicationContext factory=new ClassPathXmlApplicationContext("classpath:appcontext.xml");
ApplicationContext factory=new ClassPathXmlApplicationContext("appcontext.xml"); // src目录下的
ApplicationContext factory=new ClassPathXmlApplicationContext("conf/appcontext.xml");// src/conf 目录下的
ApplicationContext factory=new ClassPathXmlApplicationContext("file:G:/Test/src/appcontext.xml"); 

(3) AnnotationConfigApplicationContext:基于Java的配置类加载Spring的应用上下文。避免使用application.xml进行配置。不建议使用。

ApplicationContext context=new AnnotationConfigApplicationContext(BasedJava.class);
UserInfo userInfo = (UserInfo) context.getBean(UserInfo.class);
System.out.println(userInfo.getName() + ":" + userInfo.getAddress());
--------------------------------------------------------
AnnotationConfigApplicationContext appl=new AnnotationConfigApplicationContext();
appl.register(BasedJava.class);
appl.scan("exec");
appl.refresh();//此步骤不可少
UserInfo userInfo2 = (UserInfo) appl.getBean(UserInfo.class);
System.out.println(userInfo2.getName() + ":" + userInfo2.getAddress());

3,ApplicationContext的事件机制

ApplicationContex的事件机制使观察者设计模式的实现,通过ApplicationEvent类和ApplicationListener接口,可以实现ApplicationContext的事件处理。如果容器有一个ApplicationListener Bean,每当ApplicationContext发布ApplicationEvent时,ApplicationListener Bean将自动被触发。

Spring的事件框架有两个重要成员:

  • ApplicationEvent:容器事件,必须由ApplicationContext发布。
  • ApplicationListener:监听器,可由容器中的任何监听器Bean担任。

实际上,Spring的事件机制与所有的事件机制基本相似,它们都需要由事件源、事件和事件监听器组成。只是此处的事件源是ApplicationContext,且事件必须由Java程序显式触发。

Spring的内置事件:

  • ContextRefreshedEvent:ApplicationContext容器初始化或刷新触发该事件。此处的初始化是指,所有的Bean被成功加载,后处理的Bean被检测并激活,所有的singleton Bean被预实例化,ApplicationContext容器已就绪可用。
  • ContextStartedEvent:当使用ConfigurableApplicationContext(ApplicationContext的子接口)接口的start()方法启动ApplicationContext容器时触发该事件。容器管理生命周期的Bean实例将获得一个指定的启动信号,这在经常需要停滞后重新启动的场合比较常见。
  • ContextClosedEvent:当使用ConfigurableApplicationContext(ApplicationContext的子接口)接口的close()方法关闭ApplicationContext容器时触发该事件。
  • ContextStoppedEvent:当使用ConfigurableApplicationContext(ApplicationContext的子接口)接口的stop()方法使ApplicationContext停止时触发该事件。此处的停止意味着容器管理生命周期的Bean实例将获得一个指定的停止信号,被停止的Spring容器可再次调用start()方法重新启动。
  • RequestHandledEvent:Web相关的事件,只能应用于使用DispatcherServlet的Web应用中。在使用Spring作为前端的MVC控制器时,当Spring处理用户请求结束后,系统会自动触发该事件。

程序:Spring容器的事件机制。

package Bean;import org.springframework.context.ApplicationEvent;public class EmailEvent extends ApplicationEvent {private String address;private String text;public EmailEvent(Object source) {super(source);}public EmailEvent(Object source, String address, String text) {super(source);this.address = address;this.text = text;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}public String getText() {return text;}public void setText(String text) {this.text = text;}
}

上面的EmailEvent类继承了Application类,除此之外,它就是一个普通的Java类。只要一个Java类继承了ApplicationEvent积累,那该对象可作为Spring容器的容器事件。

容器事件的监听器类必须实现ApplicationListener接口,实现该接口必须实现如下方法:

  • onApplicationEvent(ApplicationEvent event):每当容器内发生任何事件时,此方法就会被触发。
package Bean;import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;public class EamilNotifier implements ApplicationListener {public void onApplicationEvent(ApplicationEvent applicationEvent) {//只处理EmailEvent事件,模拟发送if (applicationEvent instanceof EmailEvent){EmailEvent emailEvent = (EmailEvent) applicationEvent;System.out.println("需要发送邮件的地址为:"+emailEvent.getAddress());System.out.println("需要发送邮件的内容为:"+emailEvent.getText());}else{//其他事件不做任何处理System.out.println("其他事件:"+applicationEvent);}}
}

将监听器注入Spring容器。

<bean class="Bean.EamilNotifier"></bean>

当系统创建Spring容器、加载Spring容器时会自动触发容器事件,容器事件监听器可以监听到这些事件。除此之外,程序可调用ApplicationContext的publisEvent()方法主动触发容器事件。

import Bean.EmailEvent;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {public static void main(String[] args) throws BeansException {ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");EmailEvent emailEvent = new EmailEvent("test","1966799809@qq.com","你好");context.publishEvent(emailEvent);}
}
===================================================
其他事件:org.springframework.context.event.ContextRefreshedEvent[source=org.springframework.context.support.ClassPathXmlApplicationContext@446cdf90, started on Sat Jan 23 16:24:55 CST 2021]
需要发送邮件的地址为:1966799809@qq.com
需要发送邮件的内容为:你好

从结果可以看出,监听器不仅监听到程序所触发的事件也坚挺到容器内置的事件。实际上,如果开发者需要在Spring容器初始化、销毁时回调自定义方法,就可以通过上面的事件监听器来实现。

4,ApplicationContext源码(非官方)

import java.lang.reflect.*;
import java.util.*;
import java.io.*;
import org.dom4j.*;
import org.dom4j.io.*;public class MyApplicationContext implements ApplicationContext
{// 保存容器中所有单例模式的Bean实例private Map<String , Object> objPool= Collections.synchronizedMap(new HashMap<String , Object>());// 保存配置文件对应的Document对象private Document doc;// 保存配置文件里的根元素private Element root;public MyApplicationContext(String filePath)throws Exception{SAXReader reader = new SAXReader();doc = reader.read(new File(filePath));root = doc.getRootElement();initPool();initProp();}public Object getBean(String name)throws Exception{Object target = objPool.get(name);// 对于singleton Bean,容器已经初始化了所有Bean实例,直接返回即可if (target.getClass() != String.class){return target;}else{String clazz = (String)target;// 对于prototype对象并未注入属性值return Class.forName(clazz).newInstance();}}// 初始化容器中所有singleton Beanprivate void initPool()throws Exception{// 遍历配置文件里的每个<bean.../>元素for (Object obj : root.elements()){Element beanEle = (Element)obj;// 取得<bean.../>元素的id属性String beanId = beanEle.attributeValue("id");// 取得<bean.../>元素的class属性String beanClazz = beanEle.attributeValue("class");// 取得<bean.../>元素的scope属性String beanScope = beanEle.attributeValue("scope");// 如果<bean.../>元素的scope属性不存在,或为singletonif (beanScope == null ||beanScope.equals("singleton")){// 以默认构造器创建Bean实例,并将其放入objPool中objPool.put(beanId , Class.forName(beanClazz).newInstance());}else{// 对于非singlton Bean,存放该Bean实现类的类名。objPool.put(beanId , beanClazz);}}}// 初始化容器中singleton Bean的属性private void initProp()throws Exception{// 遍历配置文件里的每个<bean.../>元素for (Object obj : root.elements()){Element beanEle = (Element)obj;// 取得<bean.../>元素的id属性String beanId = beanEle.attributeValue("id");// 取得<bean.../>元素的scope属性String beanScope = beanEle.attributeValue("scope");// 如果<bean.../>元素的scope属性不存在,或为singletonif (beanScope == null ||beanScope.equals("singleton")){// 取出objPool的指定的Bean实例Object bean = objPool.get(beanId);// 遍历<bean.../>元素的每个<property.../>子元素for (Object prop : beanEle.elements()){Element propEle = (Element)prop;// 取得<property.../>元素的name属性String propName = propEle.attributeValue("name");// 取得<property.../>元素的value属性String propValue = propEle.attributeValue("value");// 取得<property.../>元素的ref属性String propRef = propEle.attributeValue("ref");// 将属性名的首字母大写String propNameCamelize = propName.substring(0 , 1).toUpperCase() + propName.substring(1 , propName.length());// 如果<property.../>元素的value属性值存在if (propValue != null && propValue.length() > 0){// 获取设值注入所需的setter方法Method setter = bean.getClass().getMethod("set" + propNameCamelize , String.class);// 执行setter注入setter.invoke(bean , propValue);}if (propRef != null && propRef.length() > 0){// 取得需要被依赖注入的Bean实例Object target = objPool.get(propRef);//objPool池中不存在指定Bean实例if (target == null){// 此处还应处理Singleton Bean依赖prototype Bean的情形}// 定义设值注入所需的setter方法Method setter = null;// 遍历target对象所所实现的所有接口for (Class superInterface : target.getClass().getInterfaces()){try{// 获取设值注入所需的setter方法setter = bean.getClass().getMethod("set" + propNameCamelize , superInterface);// 如果成功取得该接口对应的方法,直接跳出循环break;}catch (NoSuchMethodException ex){// 如果没有找到对应的setter方法,继续下次循环continue;}}// 如果setter方法依然为null,// 则直接取得target实现类对应的setter方法if (setter == null){setter = bean.getClass().getMethod("set" + propNameCamelize , target.getClass());}// 执行setter注入setter.invoke(bean , target);}}}}}
}

5,让Bean获取Spring容器

之前所说,都是程序先创建Spring容器,再调用Spring容器的getBean()方法来获取Spring容器中的Bean。在这种访问模式下,程序中总是持有Spring容器的引用。但在Web应用中,Spring容器通常采用声明式方式配置产生:开发者只要在web.xml文件中配置一个Listener,该Listener将会负责初始化Spring容器,前端MVC框架可以直接调用Spring中的Bean,无须访问Spring容器本身。这种情况下,容器中的Bean处于容器管理下,无须主动访问容器,只需接受容器的依赖注入即可。

在某些特殊的情况下,Bean需要实现某个功能,但该功能必须借助Spring容器才能实现,此时就必须让该Bean先获取Spring容器,然后借助于Spring容器来实现该功能。

为了让Bean获取它所在的Spring容器,可以让Bean实现BeanFactoryAware接口。Spring调用接口中的方法将Spring容器作为参数传入该方法。

package org.springframework.context;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.Aware;public interface ApplicationContextAware extends Aware {void setApplicationContext(ApplicationContext var1) throws BeansException;
}

Spring容器会检查容器中的所有Bean,如果发现某个Bean实现了ApplicationContextAware接口,Spring容器会在创建该Bean之后,自动调用该Bean的setApplicationContextAware()方法,调用该方法时,会将容器本身作为参数传给该方法——该方法的实现部分将Spring掺入的参数赋值给该Person的applicationContext实例变量,因此接下来即可通过该applicationContext实例变量来访问容器本身。 

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;public class Person implements ApplicationContextAware {private ApplicationContext applicationContext;public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}public void sayHi(String name){}
}

Spring:Spring容器(BeanFactory和ApplicationContext)相关推荐

  1. Spring IoC容器:BeanFactory和ApplicationContext谁才是Spring IoC容器

    private static void whoIsIoCContainer(UserRepository userRepository, ApplicationContext applicationC ...

  2. Spring系列之beanFactory与ApplicationContext

    一.BeanFactory BeanFactory 是 Spring 的"心脏".它就是 Spring IoC 容器的真面目.Spring 使用 BeanFactory 来实例化. ...

  3. spring中的BeanFactory与ApplicationContext的作用和区别?

    作用:1. BeanFactory负责读取bean配置文档,管理bean的加载,实例化,维护bean之间的依赖关系,负责bean的声明周期. 2. ApplicationContext除了提供上述Be ...

  4. BeanFactory和ApplicationContext的区别

    BeanFactory和ApplicationContext的区别 1.BeanFactory BeanFactory是Spring里面最底层的接口,提供了最简单的容器的功能,只提供了实例化对象和拿对 ...

  5. BeanFactory与ApplicationContext的区别

    BeanFactory与ApplicationContext的区别? 一.BeanFactory和ApplicationContext 接口及其子类图 二.概述 BeanFactory和Applica ...

  6. 什么是spring?spring组成模块、spring优缺点、应用场景、bean的生命周期、线程并发问题

    什么是spring 在不同的语境中,Spring 所代表的含义是不同的.下面我们就分别从"广义"和"狭义"两个角度,对 Spring 进行介绍. 广义的 Spr ...

  7. Spring 的IOC容器系列的设计与实现:BeanFactory 和 ApplicationContext

    在Spring IOC容器的设计中,我们可以看到两个主要的容器系列,一个是实现BeanFactory接口的简单容器系列,这系列容器只实现了容器的最基本的功能,另一个是ApplicationContex ...

  8. Spring IoC(一)IoC容器的设计与实现:BeanFactory与ApplicationContext

    在写BeanFactory与ApplicationContext 之前,我想先简单聊一聊Spring IoC 容器,希望能给大家一个参考.如果你对这反面的知识比较了解,可以直接跳过. (一)Sprin ...

  9. SSM 整合 4:Spring IoC 容器基于的两个重要接口 BeanFactory 和 ApplicationContext

    文章目录 前言 一.BeanFactory 接口 1.1.加载 Spring 配置文件创建 BeanFactory 接口实例 1.2.开发中的运用以及使用说明 二.ApplicationContext ...

  10. 【Spring】IoC容器系列的设计与实现:BeanFactory和ApplicationContext

    在Spring IoC容器的设计中,我们可以看到两个主要的容器系列,一个是实现BeanFactory接口的简单容器系列,这系列容器只实现了容器的最基本功能,另一个是ApplicationContext ...

最新文章

  1. 【PC工具】chrome浏览器插件vimium:传说上网可以不用鼠标。VIM入门工具,妈妈再也不用担心我学不会vim了...
  2. boost::gil::for_each_pixel用法的测试程序
  3. boost::geometry::detail::overlay::select_rings用法的测试程序
  4. 使用vant 制作导航栏
  5. ubuntu18.10运行95版仙剑
  6. 几个.net开发中常用的工具下载
  7. 线性表之顺序表与单链表的区别及优缺点
  8. kotlin 判断数字_Kotlin程序可以逆转数字
  9. 一周学C#第五天——命名空间
  10. 关于RTB实时竞价的基本原理
  11. 利用Pandas库进行简单的数据规整
  12. noSql-redis
  13. kotlin面试_Kotlin面试问题
  14. 集合之HashSet
  15. Unity 3D | 在Unity3D中创建/执行C#脚本
  16. Matlab中的对数使用
  17. 服务器装系统03系统,windows server 2003 服务器安装教程完整版
  18. 银河麒麟高级服务器操作系统V10上.NET Core与Java相同类型MySQL(MariaDB) WebApi简单性能对比
  19. Python3获取拉勾网招聘信息的方法实例
  20. NF-ResNet:去掉BN归一化,值得细读的网络信号分析 | ICLR 2021

热门文章

  1. 遇到无法拒绝的需求该怎么办
  2. Yarn 的 Shell命令
  3. 我去看Linkin Park演唱会
  4. Spring Cloud Gateway同时监听HTTP和HTTPS(http自动转发https端口)
  5. MTK客制化修改8.1系统
  6. matlab符号变量条件语句,在matlab中,能正确把x、y定义成符号变量的语句是( )...
  7. React-Native 实现安卓下载软件
  8. 计算机科技文化节答辩活动主持稿,校园宿舍文化节活动主持词范例
  9. Bomb后端云exception9015,请检查网络是否可用!
  10. WIn7 重启显示0xc000000e