目录
1. 创建 Spring 项目
1.1 创建一个 maven 项目
1.2 添加 Spring 框架支持
1.3 添加启动类
2. 存储 Bean 对象
2.1 创建 Bean
2.2 将 Bean 注册到容器
3. 获取并使用 Bean 对象
3.1 创建 Spring 上下文
ApplicationContext 和 BeanFactory 的区别(重点)
3.2 获取指定的 Bean 对象
3.2.1 通过 id 获取
3.2.2 通过类型获取
3.2.3 通过 id + 类型 获取
3.3 使用 Bean
4. Spring 创建和使用总结
5. 根据日志定位问题
5.1 NoUniqueBeanDefinitionException -- 无唯一BeanDefinition异常
5.2 BeanDefinitionParsingException -- BeanDefinition解析异常
5.3 FileNotFoundException -- 文件未找到异常
5.4 NoSuchBeanDefinitionException -- 没有这样的对象
在上篇文章中,我们了解了 Spring 的核心与设计思想:Spring 是一个包含了众多工具方法的 IoC 容器。Spring 具备的两个功能:
- 将对象存储到 Spring 中
- 从 Spring 中将对象取出来
在 Java 中,对象也叫 Bean。
1. 创建 Spring 项目
接下来我们使用 maven 方式来创建一个 Spring 项目,分以下三步:
- 创建⼀个普通 Maven 项目。
- 添加 Spring 框架支持(spring-context、spring-beans)。
- 添加启动类。
1.1 创建一个 maven 项目
1.2 添加 Spring 框架支持
<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>
添加以上代码后,刷新,显示如下图所示:
1.3 添加启动类
在创建好的项目 Java 文件夹下新创建一个包含 main 方法的启动类:
public class App {
public static void main(String[] args) {
}
}
2. 存储 Bean 对象
存储 Bean 分以下两步:
- 存储 Bean 之前,得先有 Bean,因此需要先创建一个 Bean。
- 将创建的 Bean 注册到 Spring 容器中。
2.1 创建 Bean
所谓的 Bean 是Java 语言中的一个普通对象,实现代码如下:
public class User {
public String sayHi(String name){
return name + "Hi";
}
}
2.2 将 Bean 注册到容器
<?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>
<bean id="" class=""></bean>
id 我们设置为 user,class 后应为全限定名,即带路径的名称。
那么如何知道我们的路径是否正确呢?
按住 CTRL键 鼠标点击 User 可以跳转到 User 类,则说明路径正确。
3. 获取并使用 Bean 对象
获取并使用 Bean 对象分为以下3步:
- 得到 Spring 上下文对象(因为对象都交给 Spring 管理了,所以获取对象要从 Spring 中获取,那么就需要得到 Spring 上下文)
- 通过 Spring 上下文,获取某一个指定的对象
- 使用 Bean 对象
如果获取多个 Bean 则重复第2、3步骤。
3.1 创建 Spring 上下文
ApplicationContext 可以认为是 Spring 的运行环境,翻译过来就是上下文。
使用 ApplicationContext 创建 Spring 的上下文对象,创建的时候需要配置 Spring 配置信息:
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
除了 ApplicationContext 我们还可以使用 BeanFactory 来获取 Spring 的上下文:
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("spring-config.xml"));
ApplicationContext 和 BeanFactory 的区别(重点)
ApplicationContext 和 BeanFactory 效果是一样的,ApplicationContext 属于 BeanFactory 的子类,它们有以下区别:
- 继承关系和功能方面:Spring 容器有两个顶级的接口:BeanFactory 和 ApplicationContext. 其中 BeanFactory 提供了基础的访问容器的能力,而 ApplicationContext 属于 BeanFactory 的子类,它除了继承了 BeanFactory 的所有功能之外,它还拥有独特的特性,还添加了对国际化支持、资源访问支持、以及事件传播等方面的支持。
- 从性能方面来说:ApplicationContext 是一次性加载并初始化所有的 Bean 对象(空间换时间),而 BeanFactory 是需要哪个才加载哪个(懒加载),因此更加轻量。
CalssPathXmlApplicationContext 属于 ApplicationContext 的子类,拥有 ApplicationContext 的所有功能,是通过 xml 的配置来获取所有 Bean 的。
3.2 获取指定的 Bean 对象
通过以下几种方法可以获取 Bean,最常用的为上面三种:
3.2.1 通过 id 获取
User user = (User)context.getBean("user"); // 通过 Id 获取
需要注意的是,Id 是唯一的,Bean 的 Id 需要一一对应:
3.2.2 通过类型获取
// 通过类名获取
User user = context.getBean(User.class);
优点:不需要进行类型转换
缺点:如果一个类有多个对象时,不能使用该方式
3.2.3 通过 id + 类型 获取
// 通过 id + 类型获取
User user = context.getBean("user",User.class);
那么 通过类型获取 Bean 和 id + 类型 获取 Bean 有什么区别呢?
区别:当有⼀个类型被重复注册到 spring-config.xml 中时,只能使用根据名称获取了,比如以
错误日志:Exception in thread "main" org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'BuildSpring.User' available: expected single matching bean but found 2: user,user2
可以看到错误日志大致为:期待找到一个匹配的 bean 但是 找到了两个分别是:user 和 user2.
User user = (User)context.getBean("user");
System.out.println(user);
User user1 = (User)context.getBean("user");
System.out.println(user1);
User user2 = context.getBean(User.class);
System.out.println(user2);
User user3 = context.getBean("user",User.class);
System.out.println(user3);
可以看到,无论获取多少次对象或者使用哪种方式获取,依然拿到的是同一个 Bean。
3.3 使用 Bean
public class App {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
// BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("spring-config.xml"));
// 通过 ID 获取
User user = (User)context.getBean("user");
// 通过类名获取
// User user = context.getBean(User.class);
// 通过 id + 类型获取
// User user = context.getBean("user",User.class);
System.out.println(user.sayHi("小明"));
}
}
4. Spring 创建和使用总结
Spring 的创建和使用的整体流程为:
- Spring 项目的创建
- 创建项目
- 引入依赖
- 创建一个启动类
- 存对象
- 创建 Bean(类)
- 将 Bean 注册到 spring-config 中
- 取对象
- 得到 Spring 的上下文,并读取到 Spring 的配置文件(ApplicationContext)
- 获取某一个 Bean 的对象(getBean())
- 使用 Bean 对象
5. 根据日志定位问题
日志只有一段时只看一段的最前面就可以(从上往下看),当有多段时从下往上看。
5.1 NoUniqueBeanDefinitionException -- 无唯一BeanDefinition异常
Exception in thread "main" org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'BuildSpring.User' available: expected single matching bean but found 2: user,user2
期待找到一个匹配的 bean 但是找到了两个分别是:user 和 user2。
5.2 BeanDefinitionParsingException -- BeanDefinition解析异常
Exception in thread "main" org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Bean name 'user' is already used in this <beans> element
Offending resource: class path resource [spring-config.xml]
Bean名称“user”已在此<beans>元素路径资源[spring config.xml]中使用。
5.3 FileNotFoundException -- 文件未找到异常
Caused by: java.io.FileNotFoundException: class path resource [spring-config1.xml] cannot be opened because it does not exist
at org.springframework.core.io.ClassPathResource.getInputStream(ClassPathResource.java:180)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:331)
... 13 more
[spring-config1.xml]无法打开,因为它不存在。
5.4 NoSuchBeanDefinitionException -- 没有这样的对象
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'user1' available
没有名为“user1”的bean可用。