## 第一个 Spring 程序
### 实验环境搭建
**软件版本**
```
JDK 1.8
Maven 3.6.1
IDEA 2019.3
SpringFramework 5.1.4
JUnit 4.11
```
**pom 依赖**
```xml
org.springframework
spring-context
5.1.4.RELEASE
```
**Spring 配置文件**
Spring 配置文件的存放位置和名字没有硬性规定,但是 Web 项目建议放在 `main/resources` 目录下,该目录的文件在项目构建后会放在 `WEB-INFO/classes` 下, `applicationContext.xml`
### Spring 核心 API
Spring 的核心是 `ApplicaitonContext`,这是由 Spring 提供的工厂,用于对象的创建,降低代码耦合度。实际上,`ApplicationContext`是一个接口,用来屏蔽实现的差异,例如,在 Web 环境下,我们通常使用 `XmlWebApplicationContext`,而非 Web 环境下(`main` 方法或 `junit` 单元测试中),通常使用 `ClassPathXmlApplicationContext`。
注意, `ApplicationContext` 工厂的对象是重量级资源,它会占用大量内存,不会频繁的被创建,一个应用只会创建一个工厂对象,对于多线程并发访问它一定是线程安全的
### 通过 Spring 工厂创建一个对象
创建一个 `Person` 对象,并通过该对象调用方法打印 `hello,world!`,通过 Spring 工厂创建的对象,一般就称作 Bean 或者组件(component)
1. 创建 `Person` 类
```java
package cool.yzt.domain;
public class Person {
private String name;
private int age;
public void speak() {
System.out.println("hello,world!");
}
/*
构造器、setter、getter、toString
*/
}
```
2. 配置 `applicationContext.xml` 文件,在 `beans` 标签体内添加以下 `bean` 标签
```xml
```
3. 通过工厂类获取对象
```java
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Person p = (Person)ctx.getBean("person");
p.speak();
```
控制台输出
```
hello,world!
```
### Spring 工厂的相关方法
1. 无需强制类型转换的获取对象,传入类的 `class` 作为参数
```java
Person p = ctx.getBean("person",Person.class);
```
2. `` 可以只配置 `class` 属性值,在这种情况下,Spring 会为该类自动配置一个 `id` 值,一般是这种形式 `cool.yzt.domain.Person#0`,除非这个 `` **只使用一次且没有其他 `` 引用**则可以不配置 `id`,否则必须配置 `id` 值。
如果配置文件中只有一个 `` 的 `class` 属性是 `Person` 类,则可以只传入类的 `class` 作为参数获取对象,无需 `id`。
```java
Person p = ctx.getBean(Person.class);
```
3. 获取 `applicationContext.xml` 中定义的所有 `` 的 `id` 属性值
```java
String[] beanDefinitionNames = ctx.getBeanDefinitionNames();
```
4. 根据传入的类型获取`applicationContext.xml` 中定义的对应的类的所有 `id` 值
```java
String[] beanNamesForType = ctx.getBeanNamesForType(Person.class);
```
5. 判断是否存在指定 `id` 值的 ``,两个方法皆可
```java
boolean flag1 = ctx.containsBeanDefinition("person");
boolean flag2 = ctx.containsBean("person");
```
### 简单分析 Spring 工厂底层实现
1. Spring 通过 `ClassPathXmlApplicationContext` 工厂读取 `applicationContext.xml` 读取配置文件
2. Spring 获取 `` 标签的相关信息,例如类的全类名和 `id` 值,然后通过反射创建对象
```java
Class> clazz = Class.forName(class的值);
id的值 = clazz.newInstance();
```
3. 反射创建对象也会调用类的构造方法,即使构造方法是私有的
## Spring5.x 整合日志框架
使用 Spring 整合日志框架,日至框架就可以在控制台中输出 Spring 在运行过程中的一些重要信息,便于程序的调试,了解框架运行过程
**pom 依赖**
```xml
log4j
log4j
1.2.17
org.slf4j
slf4j-log4j12
1.7.25
test
```
**log4j.properties 配置文件**
```properties
# 配置根
log4j.rootLogger = debug,console
# 日志输出到控制台显示
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Target=System.out
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
```
## 参考
[孙哥说Spring5](https://www.bilibili.com/video/BV185411477k)

Spring | Hello World