🐹 bean

吞佛童子2022年10月10日
  • frame
  • Spring
  • bean
大约 5 分钟

🐹 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 的创建

  1. 构造器创建
  2. 静态工厂创建
  3. 实例工厂创建

2) bean 的注入

  1. 构造器注入
  2. 属性注入
  3. setter 注入

5. bean 的自动装配

1) 自动装配是什么?

  • 我们通过 某种规则 向 Spring 容器告知想要的 bean
  • Spring 容器根据我们的要求对容器中的 bean 进行 自动装配,而无需通过显式的方式进行依赖配置

2) Spring 提供的自动装配类型

  1. byName
    • 通过 名称 进行自动装配
  2. byType
    • 通过 类型 进行自动装配
  3. constructor
    • byType 类似,但它是针对 构造函数 注入
  4. autodetect
    • 根据 Bean 的自省机制决定到底采用 byType 还是 constructor 自动装配

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 的线程安全?

  1. 将 bean 设置作用域为多例 bean,在 类上添加注解 @Scope("prototype") | @Scope("request")
    • 每个线程请求对应一个 bean,但这样不利于管理 bean
  2. 在 bean 对象中尽量避免定义可变的成员变量,保证多线程下返回同一个结果
  3. 使用 JUC 下并发安全的数据结构
  4. 将 bean 中的 成员变量 保存至 ThreadLocal
    • 可以保证多线程下变量的隔离
    • 但由于 web 服务器默认的请求线程池为 10,线程会服用,因此只能保证并发下 10 个线程相互隔离,超出这个情况后,多余线程会分配到前面的 10 个线程中
    • 因此,ThreadLocal 本身可以起到线程隔离的效果,但是 web 服务器达不到并发安全的效果
  5. 分布式 | 微服务下的并发安全
    • 借助 Redis 等保证同一服务下的不同实例拥有同一份共享信息
上次编辑于: 2022/10/10 下午8:43:48
贡献者: liuxianzhishou