Spring - 14 ( 5000 字 Spring 入门级教程 )
一:Spring原理
1.1 Bean 作用域的引入
在 Spring 的 IoC 和 DI 阶段,我们学习了 Spring 如何有效地管理对象。主要内容包括:
- 使用 @Controller、@Service、@Repository、@Component、@Configuration 和 @Bean 注解来声明 Bean 对象。
- 通过 ApplicationContext 或 BeanFactory 获取对象实例。
- 通过 @Autowired、Setter 方法或构造方法等方式将所依赖的 Bean 对象注入到应用程序中。
Bean 的作用域指的是 Bean 在 Spring 框架中的特定行为模式。例如,单例作用域表示同一个 Bean 在整个 Spring 容器中只有一个实例,是全局共享的。如果一个 Bean 的值被某个组件修改,则其他组件读取到的将是被修改后的值,这是 Spring 默认采用的行为模式。
1.2 Bean 作用域
在 Spring 中,共支持六种作用域,其中后四种作用域仅在 Spring MVC 环境中有效:
- singleton:单例作用域,表示整个 Spring 容器中同名称的 Bean 只有一个。
- prototype:原型作用域又叫做多例作用域,表示每次使用该 Bean 的时候都会创建一个新的。
- request:请求作用域,表示在一次 HTTP 请求中创建一个 Bean 实例,该实例在请求结束后销毁。
- session:会话作用域,表示在一个 HTTP 会话中只存在一个 Bean 实例,直到会话结束。
- application:全局作用域,表示在整个应用上下文中只有一个 Bean 实例。
- websocket:HTTP WebSocket 作用域,表示在 WebSocket 会话中只存在一个 Bean 实例。
下面一起来看看代码吧:
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Component;
import org.springframework.web.context.annotation.RequestScope;
import org.springframework.web.context.annotation.SessionScope;
import org.springframework.web.context.annotation.ApplicationScope;
@Component
public class DogBeanConfig {
@Bean
public Dog dog() {
Dog dog = new Dog();
dog.setName("旺旺");
return dog;
}
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
public Dog singleDog() {
return new Dog();
}
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Dog prototypeDog() {
return new Dog();
}
@Bean
@RequestScope
public Dog requestDog() {
return new Dog();
}
@Bean
@SessionScope
public Dog sessionDog() {
return new Dog();
}
@Bean
@ApplicationScope
public Dog applicationDog() {
return new Dog();
}
}
下面测试不同作用域的 Bean 取到的对象是否⼀样:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DogController {
@Autowired
private Dog singleDog;
@Autowired
private Dog prototypeDog;
@Autowired
private Dog requestDog;
@Autowired
private Dog sessionDog;
@Autowired
private Dog applicationDog;
@Autowired
private ApplicationContext applicationContext;
@RequestMapping("/single")
public String single() {
Dog contextDog = (Dog) applicationContext.getBean("singleDog");
return "dog: " + singleDog.toString() + ", contextDog: " + contextDog.toString();
}
@RequestMapping("/prototype")
public String prototype() {
Dog contextDog = (Dog) applicationContext.getBean("prototypeDog");
return "dog: " + prototypeDog.toString() + ", contextDog: " + contextDog.toString();
}
@RequestMapping("/request")
public String request() {
Dog contextDog = (Dog) applicationContext.getBean("requestDog");
return "dog: " + requestDog.toString() + ", contextDog: " + contextDog.toString();
}
@RequestMapping("/session")
public String session() {
Dog contextDog = (Dog) applicationContext.getBean("sessionDog");
return "dog: " + sessionDog.toString() + ", contextDog: " + contextDog.toString();
}
@RequestMapping("/application")
public String application() {
Dog contextDog = (Dog) applicationContext.getBean("applicationDog");
return "dog: " + applicationDog.toString() + ", contextDog: " + contextDog.toString();
}
}
下面观察一下 Bean 的作用域:
- 单例作用域:http://127.0.0.1:8080/single
多次访问后获得的都是同一个对象,同时使用 @Autowired 注入的对象和通过 applicationContext.getBean() 获取的对象也是相同的实例。
- 多例作用域:http://127.0.0.1:8080/prototype
观察 contextDog,每次获取的对象都是不同的。因为注入的对象在 Spring 容器启动时就已经注入,因此在多次请求中,注入的对象不会发生变化。
- 请求作用域:http://127.0.0.1:8080/request
在一次请求中,@Autowired 注入的对象和通过 applicationContext.getBean() 获取的对象是同一个实例。然而,在每次请求中,applicationContext.getBean() 会重新创建新对象。
- 会话作用域:http://127.0.0.1:8080/session
在同一个会话中,经过多次请求后获取到的对象都是相同的。然而,当换用另一个浏览器访问时,会重新创建一个新的对象,因为这将启动一个不同的会话。
- Application 作用域:http://127.0.0.1:8080/application
在一个应用中,多次访问返回的都是同一个对象。Application scope 表示 Bean 的作用域是 ServletContext 级别,这与 singleton 类似,但二者之间有一定区别:Application scope 是 ServletContext 的单例,而 singleton 是 ApplicationContext 的单例。在一个 Web 容器中,可以存在多个 ApplicationContext。
1.2 Bean 的生命周期
生命周期指的是一个对象从创建到销毁的整个过程,通常称为对象的生命周期。Bean 的生命周期可以分为以下五个部分:
- 实例化:为 Bean 分配内存空间。
- 属性赋值:进行 Bean 注入和装配,例如 @Autowired。
- 初始化:执行各种通知和初始化方法。
- 使用 Bean:在应用中使用已配置的 Bean。
- 销毁 Bean:通过容器的各种销毁方法。
import com.example.demo.component.UserComponent;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Component
public class BeanLifeComponent implements BeanNameAware {
private UserComponent userComponent;
public BeanLifeComponent() {
System.out.println("执行构造函数");
}
@Autowired
public void setUserComponent(UserComponent userComponent) {
System.out.println("设置属性 userComponent");
this.userComponent = userComponent;
}
@Override
public void setBeanName(String s) {
System.out.println("执行了 setBeanName 方法:" + s);
}
@PostConstruct
public void postConstruct() {
System.out.println("执行 PostConstruct()");
}
public void use() {
System.out.println("执行了 use 方法");
}
@PreDestroy
public void preDestroy() {
System.out.println("执行:preDestroy()");
}
}
1.3 源码阅读
这里等作者好好研究一下,研究好了再来补充。。。。
二:Spring Boot 自动配置
Spring Boot 的自动配置是在 Spring 容器启动后,自动将一些配置类和 Bean 对象存入 IoC 容器,无需手动声明,从而简化了开发,减少了繁琐的配置操作。自动配置的核心在于 Spring Boot 如何将依赖的 Jar 包中的配置类和 Bean 加载到 Spring IoC 容器中。我们学习的内容主要分为以下两个方面:
- Spring 是如何把对象加载到 Spring IoC 容器中的
- SpringBoot 是如何实现的
2.1 占位
占个位,等作者研究好了过来补充一下。。。。。。