Spring原理
Bean的作用域
1. 从@Autowired 注入的Bean 和 从ApplicationContext.getBean 获取的 Bean是同一个
1. Bean的作用域: 指的是Bean在Spring框架中的某种行为模式 2. @Bean 默认创建的就是 单例的 ,它的作用域就是: 只有一份的,全局共享的,修改了之后,再读取这个Bean,就是修改之后的值
Bean的作用域
Spring支持6种作用域, 后4中只有在SpringMVC下才支持 ;
-
singleton: 单例作用域(默认)
-
prototype: 原型作用域(多例作用域 (和单例反过来))
-
request: 请求作用域
-
session: 会话作用域
-
Application: 全局作用域
-
WebSocket: httpWebSocket作用域
single单例作用域
就和单例模式一样, 每个SpringIoC容器 同名的Bean只能有一个实例 (单例, 默认)
1. 无论是从 @Autowired 还是 从 ApplicationContext.getBean() 里获取到的都是同一个Bean 2. 只要有人修改Bean后 , 后面别人拿到的Bean就是修改后的Bean ; 3. 适合于 不变的量
// 专门设置为 单例作用域(虽然默认的也是) @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) @Bean public Dog singleDog(){ return new Dog() ; }
prototype多例作用域
1. 每次获取到的Bean都是不同的 2. 适合多线程状态下, 因为不同线程拿到的都是不同的, 所以修改不会影响其他地方
// 设置为多例作用域 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) @Bean public Dog prototypeDog(){ return new Dog() ; }
-
可以看到 @Autowired注入拿到的 和 ApplicationContext拿到的都不一样 , 因为每次拿到的都是不同的Bean
-
名称刷新都拿到不同的Bean

request请求作用域
1. request作用域: 一个请求作为一个作用域 2. 不同的请求获取到的不同
// 使用请求作用域 @RequestScope @Bean public Dog requestDog(){ return new Dog(); } @RequestMapping("request") public String re() { return "request: " + requestDog.toString() + " context:" + applicationContext.getBean("requestDog"); }
每发一次请求, 拿到的都是不一样的bean

session会话作用域
1. session会话作用域: 同一个会话拿到的就是相同的bean, 不同的会话拿到的就是不同bean 2. 不同的session用不同的浏览器访问就能够看得出来
//session作用域 @SessionScope @Bean public Dog sessionDog(){ return new Dog() ; } @Autowired private Dog sessionDog; @RequestMapping("session") public String se() { return "sessionDog: " + sessionDog.toString() + " context:" + applicationContext.getBean("sessionDog"); }
-
同一个浏览器上,怎么刷新,都是同一个session , 拿到的都是同一个Bean
-
不同浏览器,就是不同session,拿到的就是不同的Bean
-
不同浏览器上不同的bean

application全局作用域
1.application全局作用域,全局的,是对于整个web容器 单例的 2. 是对于整个ServletContext 的,单例唯一的 3. 和 single有点类似,但single是作用于 ApplicationContext的 单例 ,只在一个SpringIoc容器里, (而一个web容器里可以有多个ApplicationContext)
// 使用Application作用域 @ApplicationScope @Bean public Dog applicationDog(){ return new Dog() ; }
Bean的生命周期
生命周期是指: 从创建到销毁的过程
Bean的生命周期分为5个部分
-
实例化(为Bean分配内存空间)
-
属性赋值(Bean注入和装配,例如@Autowired)
-
初始化
- 执行各种通知 (BeanNameAware , BeanFactoryAware , ApplicationContextAware)的接口方法
- 执行各种初始化方法 (xml定义的 , 注解 @PostConstruct , 初始化后置方法 BeanPostProcessor)
4. 使用Bean
5. 销毁Bean
销毁容器的方法: @PreDestroy 方法
1. 实例化和 属性赋值(注入) 对应构造方法 和 setter方法的注入 ; 2. 初始化 和 销毁 是用户能够自定义的扩展 , 例如: 在初始化Bean时或 销毁Bean时 , 做一些 事情
模拟实现
// 通过TestBean模拟实现Bean的生命周期 @RestController public class TestBean { public TestBean() { log.info("执行实例化方法,.."); } private Dog dog ; // 使用setter方便我们观察属性赋值 @Autowired public void setDog(Dog dog) { this.dog = dog; log.info("执行setter方法 , 属性赋值..."); } @PostConstruct public void init(){ log.info("执行init 初始化方法 ..."); } public void use(){ log.info("执行user,使用Bean方法"); } @PreDestroy public void destroy(){ log.info("执行destroy销毁方法"); } } // test方法就执行一个use使用 bean @SpringBootTest class SpringyuanliApplicationTests { @Autowired private TestBean testBean ; @Test void contextLoads() { // 执行一次use, 使用Bean testBean.use(); } }

源码
AbstractAutowireCapableBeanFactory类的createBean方法
SpringBoot自动配置
Spring加载Bean
1.Spring扫描路径,就是启动类所在的路径
1.由@SpringBootApplication 标记的类就是 SpringBoot项目的启动类
2.@ComponentScan
1.通过@ComponentScan ("路径") 或 @ComponentScan({"路径1"},{"路径2"})(支持数组形式) 指定 Spring扫描的路径 2.@SpringBootApplication 能扫描到注解添加的Bean ,就是也有这个注解, 如果没有特别指定, 默认就是@SpringBootApplication所在的路径, 也就是启动类所在的路径
3.@Import
1. 使用@Import(指定类.class) , 也能将指定的Bean导入SpringIoc容器
在启动类加上, 就可以添加这个类的Bean
