美文网首页我爱编程
Spring框架基础

Spring框架基础

作者: 乛小小白 | 来源:发表于2018-04-12 15:41 被阅读0次

    Spring框架的核心功能:

    1. Spring 容器作为超级大工厂,负责创建、管理所有的Java对象,这些Java对象被称为 Bean。
    2. Spring 容器管理容器中 Bean 之间的依赖关系,Spring 使用一种被称为“依赖注入”的方式来管理 Bean 之间的依赖关系。

    当某个Java对象(调用者)需要调用另一个Java对象(被调用者)的方法时,传统方式:

    • 原始做法:调用者主动创建被依赖的对象,然后再调用被依赖对象的方法
    • 简单工厂模式:调用者先找到被依赖的工厂,然后主动通过工厂去获取被依赖对象,最后再调用被依赖对象的方法。

    使用依赖注入,不仅可以为 Bean 注入普通的属性值,还可以注入其它 Bean 的引用。通过这种依赖注入,Java EE 应用中的各个组件不需要以硬编码的方式耦合在一起,甚至无需使用工厂模式。调用者获取被依赖对象的方式由原来的主动获取,变成被动接受,即控制反转。控制反转和依赖注入其实是同一种行为的两种表达,只是描述的角度不同而已。

    依赖注入的两种方式:

    设值注入

    IoC 容器使用成员变量的setter方法来注入被依赖对象。
    <property name="axe" ref="steelAxe"></property>

    构造注入

    IoC容器使用构造器来注入被以来对象:直接调用有参数的构造器,当Bean实例创建完成之后,已经完成了依赖关系的注入
    <constructor-arg ref ="steelAxe"></constructor-arg>

    两种方式对比

    这两种注入方式没有绝对的好坏,只是适应的场景有所不同

    设值注入的优点:
    • 与传统的 JavaBean的写法相比,程序开发人员更容易理解、接受。通过setter方法设定依赖关系显得更加直观自然。
    • 对于复杂的依赖关系,采用构造注入会导致构造器过于臃肿,难以阅读。
    • 尤其在某些成员变量可选的情况下,多参数的构造器更加笨重。
    构造注入的优点:
    • 构造注入可以在构造器中决定依赖关系的注入顺序,优先依赖的优先注入。
    • 对于依赖关系无需变化的Bean,构造注入更有用处。因为没有setter方法,所有的依赖关系全部在构造器内设定。因此无需担心后续代码对依赖关系产生破坏。
    • 依赖关系只能在构造器中设定,只有组件的创建者才能改变组件的依赖关系。对于组件的调用者而言,组件内部的依赖关系完全透明,更符合高内聚的原则。

    建议采用以设值注入为主,构造注入为辅的注入策略。对于依赖关系无变化的注入,尽量采用构造注入;而其它依赖关系的注入,则考虑采用设值注入。

    Spring容器

    Spring容器最基本的接口是BeanFactory,它负责配置、创建、管理Bean,它有一个子接口:ApplicationContext,因此也被成为Spring上下文。Spring容器还负责管理Bean与Bean之间的依赖关系。
    BeanFactory接口包含以下几个基本方法:

    boolean containsBean(String name);
    <T> T getBean(Class<T> requiredType);
    Object getBean(String name);
    <T> T getBean(String name, Class RequiredType);
    Class<?> getType(String name);
    

    ApplicationContext是BeanFactory的子接口,对于大部分的Java EE 应用而言,使用它作为Spring容器更为方便,其常用实现类:FileSystemXmlApplicationContext、ClassPathXmlApplicationContext和AnnotationConfigApplicationContext。如果在Web应用中使用Spring容器,则通常有XmlWebApplicationContext、AnnotationCongifWebApplicationContext两个实现类。
    ApplicationContext允许以声明式方式操作容器,无需手动创建。除了提供BeanFactory所支持的全部功能之外,还有如下额外的功能:

    • 默认初始化所有的singleton Bean(系统前期创建ApplicationContext将会有较大的系统开销,一旦初始化完成,程序后面获取singleton Bean实例将会拥有较好的性能),也可以通过配置取消预初始化(lazy-init="true")。
    • 继承MessageSource接口,因此提供国家化支持。
    • 资源访问。
    • 事件机制。
    • 同时加载多个配置文件。
    • 以声明式方式启动并创建Spring容器。

    创建Bean的三种方式

    1. 使用构造器创建Bean实例
    2. 使用静态工厂方法创建Bean实例
      <Bean.../>元素需要制定两个属性:
    • class:该属性值设置为静态工厂类的类名
    • factory-method:该属性指定静态工厂方法来生产Bean实例
      若静态工厂方法需要参数,则使用<constructor-arg.../>元素传入
    1. 使用实例工厂方法创建Bean实例
      <Bean.../>元素需要制定两个属性:
    • factory-bean:该属性值设置为工厂Bean的id
    • factory-method:该属性指定实例工厂方法来生产Bean实例

    使用这种方法时,必须将实例工厂配置成Bean的还是理;而配置静态工厂方法创建Bean时无需配置工厂Bean。

    深入理解容器中的Bean

    Spring框架绝大部分工作都集中在对容器中Bean的管理上,包括管理容器中Bean的生命周期,使用Bean继承等。

    抽象Bean和子Bean

    将多个<bean.../>配种中相同的信息提取出来,集中成配置模板——这个配置模板不是真正的Bean,Spring容器不应该创建该配置模板,于是需要为该<bean.../>增加abstract="true",即抽象Bean。抽象Bean不能实例化。
    将大部分相同信息配置成抽象Bean之后,将实际的Bean实例配置成该抽象Bean的子Bean即可。子Bean定义可以从父Bean继承实现类,构造参数、属性值等配置信息。除此之外,子Bean配置可以增加新的配置信息,并可指定新的配置信息覆盖父Bean的定义。

    Bean继承与Java继承的区别
    1. 子Bean和父Bean可以是不同的类型
    2. Bean的继承是实例之间的关系,主要表现为参数值的延续
    3. 子Bean不可以作为父Bean使用,不具有多态性
    获取Bean本身的id

    可借助Spring提供的 BeanNameAware接口,实现该接口,并实现该接口提供的setBeanName()方法。这个方法会在容器创建完该Bean之后,由Spring容器自动调用。

    强制初始化Bean

    为了显示指定被依赖Bean在目标Bean之前初始化,可以使用depends-on属性,该属性可以在初始化主调Bean之前,强制初始化一个或多个Bean。

    容器中Bean的生命周期

    Spring可以管理singleton 作用于的Bean的生命周期,可以精确地知道该Bean何时被创建、何时被初始化完成、容器何时准备销毁该Bean实例。
    对于prototype作用域的Bean,Spring仅仅负责创建,创建完成之后,Bean实例完全交给客户端代码管理,容器不再跟踪其生命周期。
    两个时机:

    1. 注入依赖关系之后
    2. 即将销毁Bean之前
    依赖关系注入之后的行为

    Spring提供两种方式在Bean全部属性设置成功后执行特定行为

    使用init-method属性,只是增加一个普通的方法,没有代码污染。
    实现InitializingBean接口,实现其 void afterPropertiesSet() Throws Exception方法,污染代码。
    

    若同时使用两种方式,则先执行接口中的方法,再执行属性指定的方法,下同。

    Bean销毁之前的行为

    Spring也提供了两种方式定制Bean实例销毁之前的特定行为

    使用destroy-method属性
    实现DisposableBean接口,实现void destroy() Throws Exception方法
    

    如何让Spring容器优雅地关闭呢?在JVM里注册一个关闭钩子(shutdown hook)

    AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
    // 相应的业务代码
    // 为Spring容器注册关闭钩子,程序将会在退出JVM之前关闭Spring容器
    // 并保证关闭Spring之前调用singleton Dean实例的析构回调方法。
    ctx.registerShutdownHook();
    
    协调作用于不同步的Bean

    当singleton作用域的Bean依赖prototype作用域的Bean时,Spring容器会在初始化singleton作用域的Bean之前,先创建prototype作用域的Bean,然后才初始化singleton Bean,并将prototype Bean注入到singleton Bean。在这种情况下,singleton Bean访问prototype Bean时得到的永远是最初的那个prototype Bean,会产生不同步的情况。解决方法:

    • 放弃依赖注入,代码主动向容器请求Bean实例。
    • 利用方法注入:lookup方法

    相关文章

      网友评论

        本文标题:Spring框架基础

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