🐹 bean
2022年10月10日
- frame
🐹 bean
1. bean 生命周期
存在于 BeanFactory 的类注释中
2. 案例展示
- 实例化 体现在
构造函数
- 属性赋值 体现在
setter()
- 要想实现
xxxAware
接口的方法,只需要implements xxxAware
然后重写接口提供的方法即可 - 要想实现
BeanPostProcessor
的方法,需要单独定义类实现该接口,重写其方法即可自动调用
1) 定义 bean 类
public class PersonBean implements InitializingBean, BeanFactoryAware, BeanNameAware, DisposableBean {
// 属性
private String name;
// 构造函数
public PersonBean() {
System.out.println("1. 实例化");
}
// getter() && setter()
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
System.out.println("2. 属性赋值");
}
@Override
public void setBeanName(String s) {
System.out.println("3. 调用 BeanNameAware#setBeanName 方法");
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("4. 调用 BeanFactoryAware#setBeanFactory 方法");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("6. InitializingBean#afterPropertiesSet 方法");
}
public void init() {
System.out.println("7. 自定义 init 方法");
}
@Override
public void destroy() throws Exception {
System.out.println("9. DisposableBean#destroy 方法");
}
public void destroyMethod() {
System.out.println("10. 自定义destroy 方法");
}
public void work(){
System.out.println("Bean 使用中");
}
}
2) MyBeanPostProcessor
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("5. BeanPostProcessor.postProcessBeforeInitialization 方法");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("8. BeanPostProcessor#postProcessAfterInitialization 方法");
return bean;
}
}
3) xml 配置文件
<?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">
<bean name="myBeanPostProcessor" class="com.example.spring.life.MyBeanPostProcessor" />
<bean name="personBean" class="com.example.spring.life.PersonBean"
init-method="init" destroy-method="destroyMethod">
<property name="name" value="liuxianzhishou" />
</bean>
</beans>
4) 测试
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
PersonBean personBean = (PersonBean) context.getBean("personBean");
personBean.work();
((ClassPathXmlApplicationContext) context).destroy();
}
}
3. bean 定义 & 依赖定义 的方式?
1) 直接编码
- 我们一般接触不到 直接编码 方式,但 其他方式 最终都是通过 该方式实现
2) 配置文件
- 通过 xml | properties 的配置文件,配置相应的依赖关系,Spring 就可以通过读取配置文件,从而实现 依赖关系 的注入
3) 注解
- 我们平时使用最多的方式
- 在相应地方使用 注解修饰,Spring 就会扫描注解,从而实现 bean & 依赖关系 的注入
4. bean 的创建 与 注入方式?
1) bean 的创建
- 构造器创建
- 静态工厂创建
- 实例工厂创建
2) bean 的注入
- 构造器注入
- 属性注入
- setter 注入
5. bean 的自动装配
1) 自动装配是什么?
- 我们通过 某种规则 向 Spring 容器告知想要的 bean
- Spring 容器根据我们的要求对容器中的 bean 进行 自动装配,而无需通过显式的方式进行依赖配置
2) Spring 提供的自动装配类型
byName
- 通过 名称 进行自动装配
byType
- 通过 类型 进行自动装配
constructor
- 与
byType
类似,但它是针对 构造函数 注入
- 与
autodetect
- 根据 Bean 的自省机制决定到底采用
byType
还是constructor
自动装配
- 根据 Bean 的自省机制决定到底采用
6. bean 的作用域
1) singleton
- 单例模式 存在
- bean 默认作用域
2) prototype
- 每次从 容器 中调用 bean 时,都会返回一个 新的 bean
3) request
- 每次 http 请求都会产生一个 新的 bean
- 该 bean 只在当前 http request 内有效
4) session
- 同一个 http session 共享一个 bean
- 不同 http session 产生不同 bean
5) globalSession
- 同一个全局 session 共享一个 bean
- Spring 5 中已经不存在
7. 单例 bean
1) 非线程安全
2) 如何保证 单例 bean 的线程安全?
- 将 bean 设置作用域为多例 bean,在 类上添加注解
@Scope("prototype")
|@Scope("request")
- 每个线程请求对应一个 bean,但这样不利于管理 bean
- 在 bean 对象中尽量避免定义可变的成员变量,保证多线程下返回同一个结果
- 使用 JUC 下并发安全的数据结构
- 将 bean 中的 成员变量 保存至
ThreadLocal
中- 可以保证多线程下变量的隔离
- 但由于 web 服务器默认的请求线程池为 10,线程会服用,因此只能保证并发下 10 个线程相互隔离,超出这个情况后,多余线程会分配到前面的 10 个线程中
- 因此,
ThreadLocal
本身可以起到线程隔离的效果,但是 web 服务器达不到并发安全的效果
- 分布式 | 微服务下的并发安全
- 借助 Redis 等保证同一服务下的不同实例拥有同一份共享信息