Java Spring原理 --- Bean的作用域,Bean的生命周期,Spring自动配置
文章目录
- Spring原理
- Bean的作用域
- 验证是单例的
- 多例的作用域
- request的作用域
- session的作用域
- application的作用域
- Bean的生命周期
- 代码的使用
- 源码阅读
- SpringBoot自动配置
Spring原理
Bean的作用域
- 概念:从Context中获取对象,得到的都是同一个,这种行为模式,就称为bean的作用域
多次获取,拿到的Bean的对象都是同一个

- 在Spring中支持6种作用域,后4种在Spring MVC环境才生效
(1) singleton:单例作用域
每个Spring IoC容器内同名称的bean只有一个实例(单例)(默认)
(2) prototype:原型作用域(多例作用域)
每次使用该bean时会创建新的实例(非单例)
(3) request:请求作用域
每个HTTP 请求生命周期内, 创建新的实例(web环境中, 了解)
(4) session:会话作用域
每个HTTP Session生命周期内, 创建新的实例(web环境中, 了解)
(5) Application: 全局作用域
每个ServletContext生命周期内, 创建新的实例(web环境中, 了解)
(6) websocket:HTTP WebSocket 作用域
每个WebSocket生命周期内, 创建新的实例(web环境中,了解)
验证是单例的
- 从context中获取对象
- 属性注入获取对象
@Configuration
public class BeanConfig {@Beanpublic User user1(){return new User(1,"zhangsan");}// 声明作用的范围(声明了一个单例的作用域)// 声明了一个单例的对象@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)// @Scope("singleton")@Beanpublic User singleUser(){return new User();}
}// 有多个@Autowired的时候,指定名称使用哪个@Resource(name = "singleUser")private User singleUser;@RequestMapping("scope")
@RestController
public class BeanScopeController {@Autowiredprivate ConfigurableApplicationContext context;// 有多个@Autowired的时候,指定名称使用哪个@Resource(name = "singleUser")private User singleUser;@RequestMapping("/single")public String single(){// 1. 从context中获取对象String user = (String) context.getBean("singleUser");// 2. 属性注入获取对象return "从context中获取的对象 " + System.identityHashCode(user)+ "属性注入获取的对象" + System.identityHashCode(singleUser);}
}
- 结果展示:可以看出他们获取的是同一个对象

多例的作用域
- 多例模式(原型模式)
属性注入在程序启动的时候会创建一个对象,之后再重新启动,才会改变
context获取的对象,每次重新启动都会重新获取对象,因此每次对象都会发生变化

//对象@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)@Beanpublic User prototypeUser(){return new User();}// 注解
@Resource(name = "prototypeUser")private User prototypeUser;@RequestMapping("/phototype")public String phototype(){// 1. 从context中获取对象User user = (User) context.getBean("prototypeUser");// 2. 属性注入获取对象return "从context中获取的对象 " + System.identityHashCode(user)+ "属性注入获取的对象" + System.identityHashCode(prototypeUser);}
-
展示效果:每次刷新,拿到的不是同一个对象,每次请求都会生成一个新的对象

-
出现的问题:没有验证成功的原因是我们写的是同一个User对象,@Data中的hashcode()会根据id判断他们是否是同一个对象,**这里的new User()都是同一个对象,那么这里就判断了他们是同一个对象,Spring进行了优化,**因此每次request刷新都不变,理论上每次刷新,都会创建一个新的对象,每次都会变化
这里就要使用jdk,自带的toString()方法,jdk有hashcode()方法,用自带的toString()方法,它每次new都会生成不同的对象,因此可以看出request,每次都是变化的了
所以这里不同@Data,而用@Getter和@Setter


对上面问题的再一次解释:
Spring使用了代理模式,所以代理的User,每次都是同一个


Spring中才有代理模式:

request的作用域
- @RequestScope等同于@Scope,这两者含义是一样的

- 虽然是同一个对象,但是每次请求都会重新创建对象

// request的作用域
@RequestScope@Beanpublic User requestUser(){return new User();}// 注解的方式
@Resource(name = "requestUser")private User requestUser;@RequestMapping("/request")public String request(){// 1. 从context中获取对象User user = (User) context.getBean("requestUser");// 2. 属性注入获取对象return "从context中获取的对象 " + System.identityHashCode(user)+ "属性注入获取的对象" + System.identityHashCode(requestUser);}
session的作用域
- 在不同的浏览器下,是不同的会话,自然会出现不同的地址
@SessionScope@Beanpublic User sessionUser(){return new User();}
@Resource(name = "sessionUser")private User sessionUser;@RequestMapping("/session")public String session(){// 1. 从context中获取对象User user = (User) context.getBean("sessionUser");// 2. 属性注入获取对象return "从context中获取的对象 " + System.identityHashCode(user)+ "属性注入获取的对象" + System.identityHashCode(sessionUser);}
- 效果展示:
如果是同一个浏览器,并且没有清除cookie,那么session不会发生变化

如果是不同的浏览器,就是不同的cookie,session自然会发生变化

application的作用域
-
application的作用域:在整个应用中都是同一个的,和我们的单例一样,在同一个应用中都是同一个
-
两者的区别:一个web容器中(一个tomcat中),可以部署多个服务(多个ApplicationContext),而一个Web容器中有多个ServletContext - 每个Web应用都有自己独立的ServletContext实例
一个tomcat可以启动多个web服务

@ApplicationScope@Bean("applicationUser")// 指定名字public User applicationUser(){return new User();}// 注解注入
@Resource(name = "applicationUser")private User applicationUser;@RequestMapping("/application")public String application(){// 1. 从context中获取对象User user = (User) context.getBean("applicationUser");// 2. 属性注入获取对象return "从context中获取的对象 " + user+ "属性注入获取的对象" + applicationUser;}
- 在不同的浏览器中,进行展示,都是同一个

Bean的生命周期
代码的使用
- 对象的生命周期:生命周期指的是一个对象从诞生到销毁的整个生命过程, 我们把这个过程就叫做一个对象的生命周期。
Bean 的生命周期分为以下5个部分:
2. 实例化(为Bean分配内存空间)
3. 属性赋值(Bean注入和装配, 比如 @AutoWired )
4. 初始化
a. 执行各种通知, 如 BeanNameAware , BeanFactoryAware ,
ApplicationContextAware 的接口方法.
b. 执行初始化方法
▪ xml定义 init-method
▪ 使用注解的方式 @PostConstruct
▪ 执行初始化后置方法( BeanPostProcessor )
5. 使用Bean
6. 销毁Bean
a. 销毁容器的各种方法, 如 @PreDestroy , DisposableBean 接口方法, destroy-
method
举个例子:

2. 写一个案例,来验证Bean的生命周期
// BeanLifeComponent
@Component
public class BeanLifeComponent {private User user;// 构造public BeanLifeComponent() {System.out.println("执行构造方法~");}// 属性注入// 指定注入的对象// 表示注入的user1对象@Qualifier("user1")@Autowiredpublic void setUser1(User user) {this.user = user;System.out.println("属性注入~");}// 初始化// 使用@PostConstruct实现初始化@PostConstruct // 这个用的比较多public void init(){System.out.println("执行初始化方法~");}// 使用public void use(){System.out.println("执行use方法~");}// 销毁// 基本上不会用@PreDestroy // pre表示 bean 销毁前执行,销毁的时候就直接清理对象了public void destroy(){System.out.println("执行destroy销毁方法~");}
}// 测试方法
public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(SpringConfigApplication.class, args);BeanLifeComponent lifeComponent = context.getBean(BeanLifeComponent.class);lifeComponent.use();// 有不手动点击结束进程的方式来执行destroy方法// ((AbstractApplicationContext)context).destroy();}
展示效果:

手动关闭进程:

源码阅读
了解生命周期的分类
- bean的实例化,属性注入,bean的初始化

2. 执行各种通知,这些通知都是在初始化方法之前执行,属性注入之后执行的


SpringBoot自动配置
-
这些注解的底层就是Spring自动配置的
-
元注解:是注解其他注解的注解


有选择地导入配置类

