目录
2. 存储Bean对象 (将Bean对象存入Spring容器中)
2.2 将Bean注册到容器 (将Bean存储到Spring容器中)
3.1 创建Spring上下文 (得到Spring[上下文]对象)
ApplicationContext和BeanFactory的区别
由前文我们可以知道, Spring是包含了 众多工具方法 的 IoC 容器.它有两个最基本功能: 将对象存入容器, 将对象取出容器.
1. 创建Spring项目
创建Spring和Servlet类似, 首先要先创建一个Maven项目, 然后要添加Spring框架支持(即类似于Servlet中的项目依赖, 对于Spring来说例如spring-context, spring-beans), 最后添加启动类.
下面我们以IDEA 2021.3.2作为编译器 (之后一段时间所聊的项目中都以此版本做编写代码) 创建一个Spring项目.
1.1 创建一个Maven项目
首先如果有已经打开的项目, 可以直接点击右上角的File->New->Project... , 即可打开New Project窗口;
进入创建新项目的页面, 我们先在左侧项目菜单中, 选择Maven, 然后直接选择Next;
在Next后可以看到如下页面, 下图中, 红色字迹是解释说明;
那么我们将项目名称设置为spring-demo;
点击Finish之后, IDEA就会自动加载这个项目并创建初始化好项目的初始目录;
Maven国内源配置
接下来我们需要先配置Maven的国内源, 因为从国内下载依赖网络会比较差, 就容易出错, 并且需要等待的时间是及其长的.
首先打开IDEA的Settings窗口, 但是聪明的读者会发现IDEA中有两个Settings, 可以发现这里的第一个Settings是用于当前项目的设置, 第二个Settings是用于新项目创建的Settings.
所以我们在国内源的配置中需要两个都进行一次下面仅示范当前项目Settings, 新项目Settings同理;
Settings设置如下图所示:
然后要配置文件, 进入C:\Users\25803\.m2\目录下, 新建settings.xml文件(下图中已新建好),
并将以下代码复制进settings.xml文件中并保存;
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
<mirrors>
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors>
</settings>
接下来需要重新下载jar包, 先删除本地所有的jar包, 再在IDEA的Maven设置中点击"Reload All Maven Projects"按钮重新下载jar包, 如下图.
1.2 添加Spring框架支持 (Spring依赖)
接下来就可以添加Spring依赖了, 有两种方式添加, 一种是Maven仓库中搜索关键字Spring,
选择Spring-context, 然后要注意这一块它的版本是非常多的, 这里博主选择5.x.x版本的, 原因是博主的计算机环境只安装了 jdk8 ,所以只能使用5.x.x的版本,
点击可直接复制下方的Maven代码到IDEA配置文件pom.xml中即可.
在复制的时候要注意pom.xml文件中要先新建dependencies标签,
那么这里还要注意这里面复制过来之后, 此处只是声明了我们当前的项目要去加载这个依赖, 而当前项目是否有真正把这个依赖加载进来就需要看右侧的项目结构中的"External Libraries",
我们点击展开后就会发现这里只有jdk的jar包, 而没有spring的jar包,
那么就需要点击Maven中的Reload All Maven Projects,
点击之后就会下载jar包,
下载完成之后, 就可以看到此时的spring依赖的jar包已经被下载好了.
另一种方式就是直接复制以下代码到pom.xml中.
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
</dependencies>
从上述的配置中可以看出, 添加的框架有 spring-context:spring 上下文,还有 spring-beans:管理对象的模块。
1.3 创建启动类
将启动类App建在src/main/java目录下.
public class App {
public static void main(String[] args) {
// ..
}
}
至此, 我们成功创建了一个Spring项目.
2. 存储Bean对象 (将Bean对象存入Spring容器中)
在Java中, 对象也叫做Bean, 后文再遇到对象就以Bean著称.
存储Bean分为以下2步:
- 存储Bean前, 先要有Bean才行, 因此要先创建一个Bean.
- 将创建好的Bean注册到Spring容器中.
2.1 创建Bean
public class Student {
public void sayHello(){
System.out.println("hello student!");
}
}
2.2 将Bean注册到容器 (将Bean存储到Spring容器中)
Bean的存储需要依赖于xml, 我们通过Spring的配置文件声明将对象存进即可.
在创建好的项目中添加Spring配置文件spring-config.xml (该文件名可以随意起, 但是在后面获取Bean时参数必须和文件名相同) , 将此文件放到resources个根目录下, 如下图所示:
然后将以下代码复制进该文件中:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
接下来就可以在beans标签中写需要注入的bean. 即将需要存储到Spring容器的Bean对象注册到Spring中.
注意, 需要添加id与class标签属性, 其属性填写要求如下:
- id: 写什么都可以, 但是尽量望文生义, 以小驼峰命名.
- class: 是要存放的"类名所在包.类名".
如果存放的名字是有路径的, 比如再创建一个包com.spring.demo, 将前文的Student类放入这个包的根目录中, 这个时候为了找到这个类, 就需要是"包名 + 类名"
由上我们可以填写出这样一个bean, 它的含义是: 将 bean (com.spring.demo.Student) 存到 Spring 容器中, 它的名称叫做 student (id属性).
接下来我们就可以取Bean了.
3. 获取并使用Bean对象
获取并使用Bean对象, 分为以下三步:
- 得到Spring上下文对象, 因为对象都交给Spring管理了, 所以获取对象要从Spring中获取, 那么就得先得到Spring的上下文.
- 通过Spring上下文, 获取某一个指定的Bean对象.
- 使用Bean对象.
如果要取多个Bean对象的话重复以上2, 3步骤.
3.1 创建Spring上下文 (得到Spring[上下文]对象)
获取Spring对象的方法有很多种, 那么现在最常见的是ApplicationContext (应用程序上下文), 这个应用程序上下文就是Spring上下文, 因为这个ApplicationContext来自Spring Framework, 它是Spring里面的一个命名, 那么可以认为ApplicationContext可以代表Spring本身.
ApplicationContext是一个接口, 为了得到它这个接口就需要new其子类, 它的一个子类是ClassPathXmlApplicationContext, 实现代码如下:
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");
注意ClassPathXmlApplicationContext参数与"spring-config.xml"这个文件名的对应关系.
我们在IDEA中设置keymap为eclipse之后在编译页面点击ApplicationContext类名再按下F4, 可以看到ApplicationContext的父类以及子类有哪些:
可以看到ApplicationContext是来自于springframework, 但是它本身是一个接口, 它的孙子类就有ClassPathXmlApplicationContext.
我们也可以通过ClassPathXmlApplicationContext的F4来往上看, 也能看到其父类为AbstractApplicationContext.
除了ApplicationContext之外, 我们还可以使用BeanFactory来作为Spring的上下文, 如下所示.
BeanFactory beanFactory =
new XmlBeanFactory(new ClassPathResource("spring-config.xml"));
我们可以认为, ApplicationContext和BeanFactory都是代表着Spring的, 两者效果相同, ApplicationContext属于BeanFactory的子类.
3.2 获取指定的Bean对象
// 1. 得到 Spring
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");
// 2. 从 Spring 容器中获取到 Bean 对象
Student student = (Student) context.getBean("student");
3.2.1注意事项
Bean的Id要和spring-config.xml的bean标签的id属性对应(可以随意起名字但是必须一致), 如下图所示:
3.2.2 获取Bean的3种方式
- 通过名称获取
Student student = (Student) context.getBean("student");
- 通过类型方式获取
Student student = context.getBean(Student.class);
注意: 如果Spring中一个类型存储了多个实例, 那么使用类型获取Bean就会报错!
- 通过名称 + 类型方式获取
Student student = context.getBean("student", Student.class);
3.3 使用Bean
import com.spring.demo.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main(String[] args) {
// 1. 得到 Spring
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");
// 2. 从 Spring 容器中获取到 Bean 对象
Student student = (Student) context.getBean("student");
// 3. 使用 Bean (非必须)
student.sayHello();
}
}
编写完上述代码之后我们点击运行,
可以看到, 我们成功得到了Bean对象, 并且成功了打印了Student内的方法, 所以综上我们的Spring的创建和使用就成功了.
附录
ApplicationContext和BeanFactory的区别
我们通过示例来说明它们之间的区别.
在前面创建的Spring示例项目的基础上再创建一个类:
public class App2 {
public static void main(String[] args) {
// 1. 得到 Spring 对象
BeanFactory beanFactory =
new XmlBeanFactory(new ClassPathResource("spring-config.xml"));
// 2. 从 Spring 容器中获取 Bean 对象
Student student = (Student) beanFactory.getBean("student");
// 3. 使用 Bean
student.sayHello();
}
}
执行结果和之前的示例相同, 说明这种方式也是可以正常的获取到Spring对象, 并且能够从Spring里面得到Bean对象, 那么问题是既然已经有了ApplicationContext, 那为什么要有BeanFactory? 它们的区别是什么?
接下来我们先在Student类中写入构造方法:
package com.spring.demo;
public class Student {
public Student() {
System.out.println("do Student init!");
}
public void sayHello() {
System.out.println("hello student!");
}
}
然后除了Student类之外再创建一个Teacher类, 然后将Teacher类注册到Spring容器中.
package com.spring.demo;
public class Teacher {
public Teacher() {
System.out.println("do Teacher init!");
}
public void sayHello() {
System.out.println("hi teacher!");
}
}
<bean id="teacher" class="com.spring.demo.Teacher"></bean>
执行原来ApplicationContext的App的运行代码之后是以下结果:
可以看出, ApplicationContext是执行了Student的init和Teacher的init.
我们再来看BeanFactory的执行结果:
很明显两个执行结果是不同的, BeanFactory并没有执行Teacher的init.
出现两个结果的原因是:
执行ApplicationContext的"得到 Spring 对象"代码的效果是将xml中所有的对象实例化存储到Spring容器中.
而BeanFactory是一种"懒加载(lazy load) , 它则只有调用getBean的时候, 才会加载对应的Bean.
ApplicationContext特征: 比较费内存、一次性加载,之后的读取会非常的快。
BeanFactory特征: 节省内存,调用时才会加载初始化 bean到spring 中,所以效率不高。
两者关系在IDEA中也可以看到:
面试题: ApplicationContext与BeanFactory的区别?
1. 继承关系和功能方面来说: Spring 容器有两个顶级的接口: BeanFactory 和ApplicationContext。其中 BeanFactory 提供了基础的访问容器的能力,而 ApplicationContext属于 BeanFactory 的子类,它除了继承了 BeanFactory 的所有功能之外,它还拥有独特的特性还添加了对国际化支持、资源访问支持、以及事件传播等方面的支持。
2. 从性能方面来说: ApplicationContext 是一次性加载并初始化所有的 Bean 对象,而BeanFactory 是需要哪个才去加载哪个,因此更加轻量。
PS: 而 ClassPathXmlApplicationContext 属于 ApplicationContext 的子类,拥有ApplicationContext 的所有功能,是通过 xml的配置来获取所有的 Bean 容器的。