美文网首页
Spring 与 IoC(第二讲)

Spring 与 IoC(第二讲)

作者: 辽A丶孙悟空 | 来源:发表于2020-07-29 11:40 被阅读0次
Bean 的装配

举例:Spring_Bean_Assemble 项目。
Bean 的装配,即 Bean 对象的创建。容易根据代码要求创建 Bean 对象后再传递给代码的过程,称为 Bean 的装配。

  • 默认装配方式
    代码通过 getBean() 方式从容器获取指定的 Bean 实例,容器首先会调用 Bean 类的无参构造器,创建空值的实例对象。
    举例: ba01 包





  • 动态工厂 Bean
    有些时候,项目中需要通过工厂类来创建 Bean 实例,而不能像前面例子中似的,直接由 Spring 容器来装配Bean实例。使用工厂模式创建 Bean 实例,就会使工厂类与要创建的 Bean 类耦合到一起。
    (1)将动态工厂 Bean 作为普通 Bean 使用
    将动态工厂 Bean 作为普通 Bean 来使用是指,在配置文件中注册过动态工厂 Bean 后,测试类直接通过 getBean() 获取到工厂对象,再由工厂对象调用其相应方法创建相应的目标对象。配置文件中无需注册目标对象的 Bean。因为目标对象的创建不由 Spring 容器来管理。
    举例: ba02 包





    但,这样做的缺点是,不仅工厂类与目标类耦合到一起,测试类与工厂类也耦合到了一起。
    (2)使用 Spring 的动态工厂 Bean
    Spring 对于使用动态工厂来创建的Bean,有专门的属性定义。factory- bean 指定相应的工厂 Bean,由 factory-method 指定创建所用方法。此时配置文件中至少会有两个 Bean 的定义:工厂类的 Bean,与工厂类所要创建的目标类 Bean。而测试类中不再需要获取工厂 Bean 对象了,可以直接获取目标 Bean 对象。实现测试类与工厂类间的解耦。



  • 静态工厂 Bean
    使用工厂模式中的静态工厂来创建实例 Bean。
    此时需要注意,静态工厂无需工厂实例,所以不再需要定义静态工厂 <bean/>。
    而对于工厂所要创建的 Bean,其不是由自己的类创建的,所以无需指定自己的类。但其是由工厂类创建的,所以需要指定所用工厂类。故 class 属性指定的是工厂类而非自己的类。当然,还需要通过 factory-method 属性指定工厂方法。
    举例: ba03 包



  • 容器中 Bean 的作用域
    当通过 Spring 容器创建一个 Bean 实例时,不仅可以完成 Bean 的实例化,还可以通过 scope 属性,为 Bean 指定特定的作用域。Spring 支持5种作用域。
    (1)singleton:单态模式。即在整个 Spring 容器中,使用 singleton 定义的 Bean 将是单例的,只有一个实例。默认为单态的。
    (2) prototype:原型模式。即每次使用 getBean 方法获取的同一个<bean />的实例都是一个新的实例。
    (3) request: 对于每次 HTTP 请求,都将会产生一个不同的 Bean 实例。
    (4) session:对于每个不同的HTTP session,都将产生一个不同的 Bean 实例。
    注意:
    ① 对于 scope 的值request、session与global session,只有在Web应用中使用Spring 时, 该作用域才有效。
    ② 对于 scope 为 singleton 的单例模式,该 Bean 是在容器被创建时即被装配好了。
    ③ 对于 scope 为 prototype 的原型模式,Bean 实例是在代码中使用该 Bean 实例时才进行装配的。
    举例: ba04 包



  • Bean 后处理器
    Bean 后处理器是一种特殊的 Bean,容器中所有的 Bean 在初始化时,均会自动执行该类的两个方法。由于该 Bean 是由其它 Bean 自动调用执行,不是程序员手工调用,故此 Bean 无须 id 属性。
    需要做的是,在 Bean 后处理器类方法中,只要对 Bean 类与 Bean 类中的方法进行判断,就可实现对指定的 Bean 的指定方法进行功能扩展与增强。方法返回的 Bean 对象,即是增过的对象。
    代码中需要自定义 Bean 后处理器类。该类就是实现了接口 BeanPostProcessor 的类。该接口中包含两个方法,分别在目标 Bean 初始化完毕之前与之后执行。它们的返回值为:功能被扩展或增强后的 Bean 对象。
    Bean 初始化完毕有一个标志:一个方法将被执行。即当该方法被执行时,表示该 Bean 被初始化完毕。所以 Bean 后处理器中两个方法的执行,是在这个方法之前之后执行。这个方法在后面将会讲到。
    public Object postProcessBeforelnitialization(Object bean, String beanld)
    throws BeansException 该方法会在目标 Bean 初始化完毕之前由容器自动调用。
    public Object postProcessAfterlnitialization(Object bean, String beanld) throws BeansException 该方法会在目标Bean初始化完毕之后由容器自动调用。
    它们的参数是:第一个参数是系统即将初始化的 Bean 实例,第二个参数是该 Bean 实例的 id 属性值。若 Bean 没有 id 就是 name 属性值。
    举例:
    ba05包
    程序中有一一个业务接口 IService, 其有两个业务方法 some() 与 other()。 有两个 Bean:StudentServicelmpl 与 TeacherServicelmpl,均实现了 IService 接口。
    要求:对 StudentServicelmpl 的 some() 方法进行增强,输出其开始执行时间与执行结束时间。







  • 定制 Bean 的生命始末
    可以为 Bean 定制初始化后的生命行为,也可以为 Bean 定制销毁前的生命行为。
    举例: ba06 包。
    首先,这些方法需要在 Bean 类中事先定义好:是方法名随意的 public void 方法。



    其次,在配置文件的<bean/>标签中增加如下属性:
    init-method:指定初始化方法的方法名
    destroy-method:指定销毁方法的方法名



    注意,若要看到 Bean 的 destroy-method 的执行结果,需要满足两个条件:
    (1) Bean 为 singleton,即单例
    (2)要确保容器关闭,接口 ApplicationContext 没有 close() 方法,但其实现类有。所以,可以将 ApplicationContext 强转为其实现类对象,或直接创建实现类对象。
  • Bean 的生命周期
    Bean 实例从创建到最后销毁,需要经过很多过程,执行很多生命周期方法。
    Step1:调用无参构造器,创建实例对象。
    Step2:调用参数的 setter,为属性注入值。
    Step3:若 Bean 实现了 BeanNameAware 接口,则会执行接口方法setBeanName(String beanld),使 Bean 类可以获取其在容器中的 id 名称。
    Step4:若 Bean 实现了 BeanFactoryAware 接口,则执行接口方法setBeanFactory(BeanFactory factory),使 Bean 类可以获取到 BeanFactory 对象。
    Step5:若定义并注册了 Bean 后处理器 BeanPostProcessor, 则执行接口方法
    postProcessBeforelnitialization()。
    Step6:若 Bean 实现了 InitializingBean 接口,则执行接口方法 afterPropertiesSet ()。 该方法在 Bean 的所有属性的 set 方法执行完毕后执行,是 Bean 初始化结束的标志,即 Bean 实例化结束。
    Step7:若设置了 init-method 方法,则执行。
    Step8:若定义并注册了 Bean 后处理器 BeanPostProcessor, 则执行接口方法
    postProcessAfterlnitialiation()。
    Step9:执行业务方法。
    Step10:若Bean实现了 DisposableBean 接口,则执行接口方法 destroy()。
    Step11:若设置了 destroy-method 方法,则执行。
    举例:ba07 包


  • <bean/>标签的 id 属性与 name 属性
    一般情况下,命名<bean/>使用id属性,而不使用 name 属性。在没有 id 属性的情况下,name 属性与 id 属性作用是相同的。但当<bean/>中含有一些特殊字符时,就需要使用 name 属性了。
    id 的命名需要满足 XML 对 ID属 性命名规范:必须以字母开头,可以包含字母、数字、下划线、连字符、句话、冒号。
    name 属性值则可以包含各种字符。

相关文章

网友评论

      本文标题:Spring 与 IoC(第二讲)

      本文链接:https://www.haomeiwen.com/subject/xjthrktx.html