bean创建相关

bean 创建顺序

1. 在 spring 的 ioc 容器, 默认是按照配置的顺序创建 bean 对象
<bean id="student01" class="com.hspedu.bean.Student" />
<bean id="department01" class="com.hspedu.bean.Department" />
会先创建 student01 这个 bean 对象,然后创建 department01 这个 bean 对象
2. 如果这样配置
<bean id="student01" class="com.hspedu.bean.Student" depends-on="department01"/>
<bean id="department01" class="com.hspedu.bean.Department" />
会先创建 department01 对象,再创建 student01 对象
<!--bean对象的加载顺序——默认情况下是按照写的顺序,如果有depend的话就先加载depend的的-->
    <bean class="com.recorder.spring.bean.Student" id="student" depends-on="class"/>
    <bean class="com.recorder.spring.bean.Class" id="class"/>

ioc容器会先将各个bean创建好。之后再创建各个bean之间的引用关系

bean 对象的单例和多例

在 spring 的 ioc 容器, 在默认是按照单例创建的,即配置一个 bean 对象后,ioc 容器只会创建一个 bean 实例。
如果希望 ioc 容器配置的某个 bean 对象,是以多个实例形式创建的则可以通过配置scope="prototype" 来指定
 <!--bean对象的单例和多例
    在spring的ioc容器,bean对象默认是按照单例创建的,即配置一个bean对象后,ioc容器只会创建一个bean实例(scope默认是singleton)。
    如果,我们希望ioc容器配置的某个bean对象,是以多个实例形式创建的则可以通过配置scope="prototype" 来指定-->
    <!--1. 默认是单例 singleton, 在启动容器时, 默认就会创建 , 并放入到 singletonObjects 集合-->
    <!--2. 当 <bean scope="prototype" > 设置为多实例机制后, 该 bean 是在 getBean()时才创 建-->
    <!--3. 如 果 是 单 例 singleton, 同 时 希 望 在 getBean 时 才 创 建 , 可 以 指 定 懒 加 载 lazy-init="true" (注意默认是 false)-->
    <!--4. 通常情况下, lazy-init 就使用默认值 false , 在开发看来, 用空间换时间是值得的, 除非 有特殊的要求.-->
    <!--5. 如果 scope="prototype" 这时你的 lazy-init 属性的值不管是 ture, 还是 false 都是在 getBean 时候,才创建对象.-->
    <bean class="com.recorder.spring.bean.Cat" id="cat01" scope="prototype">
        <property name="id" value="1"></property>
        <property name="name" value="咪咪"></property>
    </bean>

可以看到三只cat并不是同一个对象

bean 的生命周期

说明: bean 对象创建是由 JVM 完成的,然后执行如下方法
1. 执行构造器
2. 执行 set 相关方法
3. 调用 bean 的初始化的方法(需要配置)
4. 使用 bean
5. 当容器关闭时候,调用 bean 的销毁方法(需要配置)
演示:
public class House {
    private String name;

    public House() {

        //System.out.println("House() 构造器...");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        //System.out.println("House setName()=" + name);
        this.name = name;
    }

    //解读:
    //1. 这个方法(名字)是程序员来编写的.
    //2. 根据自己的业务逻辑来写.
    public void init() {

        //System.out.println("House init()..");
    }

    //解读:
    //1. 这个方法是程序员来编写的.
    //2. 根据自己的业务逻辑来写.
    //3. 名字也不是固定的
    public void destroy() {
        System.out.println("House destroy()..");
    }

    @Override
    public String toString() {
        return "House{" +
                "name='" + name + '\'' +
                '}';
    }
}

xml配置

<!--bean对象的生命周期-->
    <bean class="com.recorder.spring.bean.House" id="house"
          init-method="init"
          destroy-method="destroy">
        <property name="name" value="四合院"></property>
    </bean>

测试

@Test
    //bean对象的生命周期
    public void lifeCircleOfBean() {
        //创建一个容器,并和配置文件关联(一个容器关联一个配置文件)
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
        House house = ioc.getBean("house", House.class);
        System.out.println("using house" + house);
        ((ConfigurableApplicationContext) ioc).close();//销毁容器
        //输出内容:
        // House() 构造器...
        //House setName()=四合院
        //House init()..
        //using houseHouse{name='四合院'}
        //House destroy()..


    }
使用细节:
1. 初始化 init 方法和 destory 方法, 是程序员来指定
2. 销毁方法就是当关闭容器时,才会被调用

配置 bean 的后置处理器

● 说明:
1. 在 spring 的 ioc 容器,可以配置 bean 的后置处理器
2. 该处理器/对象会在 bean 初始化方法调用前和初始化方法调用后被调用
3. 程序员可以在后置处理器中编写自己的代码
● 应用实例演示
创建一个后置处理器
package com.recorder.spring.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

/**
 * @author 紫英
 * @version 1.0
 * @discription 后置处理器 需要实现 BeanPostProcessor接口
 */
public class MyBeanPostProcessor implements BeanPostProcessor {
    /**
     * 调用时机: 在Bean的init方法前被调用
     * @param bean 传入的在IOC容器中创建/配置的Bean
     * @param beanName 传入的在IOC容器中创建/配置的Bean的id
     * @return 程序员对传入的bean 进行修改/处理【如果有需要的话】,之后将其返回
     * @throws BeansException 异常
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("bean= " + beanName + " beanName= " + beanName);
        //将所有house类型的名字都转换为汤臣一品
        if (bean instanceof House){
            ((House)bean).setName("汤臣一品");
        }
        return bean;
    }

    /**
     * 调用时机: 在Bean的init方法后被调用
     * @param bean 传入的在IOC容器中创建/配置的Bean
     * @param beanName 传入的在IOC容器中创建/配置的Bean的id
     * @return 程序员对传入的bean 进行修改/处理【如果有需要的话】,之后将其返回
     * @throws BeansException 异常
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("bean= " + beanName + " beanName= " + beanName);
        return bean;
    }
}

配置xml

<!--配置house信息-->
    <bean class="com.recorder.spring.bean.House" id="house01"
          init-method="init"
          destroy-method="destroy"
    >
        <property name="name" value="大豪宅"/>
    </bean>

配置后置处理器

 <!--配置后置处理器对象
   解读:
   1. 当我们在beans02.xml 容器配置文件 配置了 MyBeanPostProcessor
   2. 这时后置处理器对象,就会作用在该容器创建的(所有)Bean对象
   3. 已经是针对所有对象编程->切面编程AOP
   -->
    <bean class="com.recorder.spring.bean.MyBeanPostProcessor" id="myBeanPostProcessor"/>
其它说明
1、怎么执行到这个方法?=> 使用 AOP(反射+动态代理+IO+容器+注解)
2、有什么用?=> 可以对 IOC 容器中所有的对象进行统一处理 ,比如 日志处理/权限的校验/安全的验证/事务管理.
-初步体验案例: 如果类型是 House 的统一改成 上海豪宅
3、针对容器的所有对象吗? 是的=>切面编程特点

 

 通过属性文件给 bean 注入值

创建my.properties

 xml配置

 <!--通过属性文件给 bean 注入值-->
    <!--如果没有成功引入 将文件修改成All problem 然后提示错误 alt + enter-->
    <!--这里的属性通过${属性名}来赋值,属性名就是my.properties文件中的k-->
    <context:property-placeholder location="classpath:my.properties"/>
    <bean class="com.recorder.spring.bean.Hero" id="hero08">
        <property name="id" value="${id}"/>
        <property name="name" value="${name}"/>
        <property name="skill" value="${skill}"/>
    </bean>

 

如果是中文需要手动转成Unicode编码,再放到my.properties中

 

 

 

posted @ 2022-10-18 20:51  紫英626  阅读(52)  评论(0)    收藏  举报

紫英