天天看点

初始Spring——Spring核心容器

一.  IOC和DI基础

  IOC-Inversion of Control,译为控制反转,是一种遵循了依赖倒置原则的代码设计思想。

  所谓依赖倒置,就是把原本的高层建筑依赖底层建筑“倒置”过来,变成底层建筑依赖高层建筑。高层建筑决定需要什么,底层去实现这样的需求,但是高层并不用管底层是怎么实现的。这样就不会出现前面的“牵一发动全身”的情况。

  而控制反转就是把传统程序中需要实现对象的创建、代码的依赖,反转给一个专门的"第三方"即容器来实现,即将创建和查找依赖对象的控制权交给容器,由容器将对象进行组合注入,实现对象与对象的松耦合,便于功能的复用,使程序的体系结构更灵活。

  

初始Spring——Spring核心容器

  DI-Dependency Injection,译为依赖注入,实际上是对Ioc的另一种称呼。2004年,大师级人物Martin Fowler为“控制反转”取了一个更合适的名字“依赖注入”。给出了实现IOC的方法:注入。所谓依赖注入,就是由IOC容器在运行期间,动态地将某种依赖关系注入到对象之中。

  理解IOC和DI的关键:

  控制反转,谁控制了谁?--IOC容器控制了对象;控制了什么?--控制了外部资源的获取(对象,文件等);哪些方面的控制被反转了?--获得依赖对象的过程被反转了。

  依赖注入,谁依赖谁?--程序依赖IOC容器;为什么需要依赖?--程序需要IOC容器来提供外部资源;谁注入谁?--IOC容器向程序注入;注入了什么?--注入某个对象所需要的外部资源。

  依赖注入(DI)和控制反转(IOC)是从不同的角度的描述的同一件事情,就是指通过引入IOC容器,利用依赖关系注入的方式,实现对象之间的解耦。

二.  Spring容器与Bean

1. spring核心容器  

spring的核心容器包括了:Beans、Core、Context、SpEL

    ① core和beans模块提供了整个框架最基础的部分,包括了IOC和DI。

    ② Context建立在Core和Beans模块提供的基础之上:他提供了框架式访问对象的方式

    ③ core、beans、context构成了Spring的骨架

    ④ SpEL:提供了一种强大的用于在运行时操作对象的表达式语言

 org.springframework.beans.factory.BeanFactory是Spring容器的实际代表者,容器负责容纳此前所描述的bean,并对bean进行管理。

2. spring与bean的关系

  Spring容器是Spring的核心,一切SpringBean都存储在Spring容器内。可以说bean是spring核心中的核心。Bean配置信息定义了Bean的实现及依赖关系,Spring容器根据各种形式的Bean配置信息来创建Bean实例,并调用Bean实例的方法来完成“依赖注入”,可以把Spring容器理解成一个大型工厂,Bean就是该工厂的产品,工厂(Spirng容器)里能生产出来什么样的产品(Bean),完全取决于配置文件中的配置。而这个配置是由开发人员创建和维护的。

3. Bean的作用域 

  spring的作用域有singleton,prototype,request,session,globle session。

  这里只讨论常用的singleton和prototype两种作用域

  对于singleton作用域,每次请求同id的Bean都将获得相同的实例,spring容器负责跟踪Bean实例状态,负责维护Bean实例的生命周期。

  对于prototype作用域,程序每次请求同id的Bean会获得新的实例,spring容器只负责创建,一旦创建成功就撒手不管,不再管理Bean实例的生命周期,也不会维护Bean实例的状态。

4. 容器中Bean的生命周期 

  Spring可以管理singleton作用域Bean的生命周期,Spring可以精确地知道singleton域bean何时被创建,何时初始化完成,以及容器何时准备销毁Bean实例。对于singleton作用域的Bean,管理Bean的生命周期行为主要有两个时机:注入依赖关系后,销毁实例之前;具体的管理方法如下

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

    使用init-method 属性(代码污染小)

            在类中编写一个方法,在属性中指定该方法在依赖关系设置完成后自动执行。

    实现InitializingBean接口(耦合较高)

            编写afterPropertiesSet()方法的具体实现

  同理,若在Bean销毁之前,执行特定的方法,只需要使用 destroy-method属性或实现DisposableBean接口(实现destroy()方法)

  对于prototype作用域的Bean,Spring容器只负责Bean的创建,当容器创建实例完成后,Bean将完全交给客户端代码管理,容器不再负责其生命周期,Spring容器本身也不知道自己创建了多少个实例,更无从知道这些实例什么时候才会被销毁。

5. Bean标签属性  

  ① id属性:Bean的名称在IOC容器中必须是唯一的。

  ② class属性:指定Bean对应实现类的全类名,即包名加类名,必须有无参构造。

  ③ scope属性: 前面提到过的作用域属性,不指定默认为singleton,即单实例模式。

  ④ name属性:设置<bean>标签的别名,多个别名之间用逗号或空格分开。

  ⑤ parent属性:子类Bean定义它所引用它的父类Bean。子类Bean定义它所引用它的父类Bean。这时前面的class属性失效。子类Bean会继承父类Bean的所有属性,子类Bean也可以覆盖父类Bean的属性。注意:子类Bean和父类Bean是同一个Java类。

  ⑥ abstract属性:用来定义Bean是否为抽象Bean。它表示这个Bean将不会被实例化,一般用于父类Bean,因为父类Bean主要是供子类Bean继承使用。

  ⑦ singleton属性:作用同③,默认为true

  ⑧ lazy-init属性:用来定义这个Bean是否实现懒初始化。如果为“true”,它将在BeanFactory启动时初始化所有的SingletonBean。反之,如果为“false”,它只在Bean请求时才开始创建SingletonBean。

  ⑨ autowire属性:它定义了Bean的自动装载方式。“no”:不使用自动装配功能。“byName”:通过Bean的属性名实现自动装配。“byType”:通过Bean的类型实现自动装配。“constructor”:类似于byType,但它是用于构造函数的参数的自动组装。“autodetect”:通过Bean类的反省机制(introspection)决定是使用“constructor”

  ⑩ dependency-check属性:它用来确保Bean组件通过JavaBean描述的所以依赖关系都得到满足。在与自动装配功能一起使用时,它特别有用。none:不进行依赖检查objects:只做对象间依赖的检查。simple:只做原始类型和String类型依赖的检查。all:对所有类型的依赖进行检查。它包括了前面的objects和simple。

  ⑪ depends-on属性:这个Bean在初始化时依赖的对象,这个对象会在这个Bean初始化之前创建。

  ⑫ init-method属性:用来定义Bean的初始化方法,它会在Bean组装之后调用。它必须是一个无参数的方法。

  ⑬ destroy-method属性:用来定义Bean的销毁方法,它在BeanFactory关闭时调用。同样,它也必须是一个无参数的方法。它只能应用于singletonBean。

  ⑭ factory-method属性:定义创建该Bean对象的工厂方法。它用于下面的“factory-bean”,表示这个Bean是通过工厂方法创建。此时,“class”属性失效。

  ⑮ factory-bean属性:定义创建该Bean对象的工厂类。如果使用了“factory-bean”则“class”属性失效。

三. spring中bean配置

bean配置有三种方法:

1、配置形式:

①基于xml文件  ②基于注解  ③基于java类

2、配置方式:

①通过全类名(反射)

②通过工厂方法(静态工厂方法、实例工厂方法)

③FactoryBean

3、依赖注入方式:

①属性注入  ②构造器注入

1. 基于xml 全类名 属性注入

<bean id="helloWorld" class="top.arioso.spring.beans.HelloWorld">
        <property name="id">
            <value>123456</value>
        </property>
        <property name="age" value="18"></property>
    </bean>
    
    property节点:为Bean属性赋值,name为属性名,value对应属性值,属性值要有setter方法
    value属性可用子节点value替代      

2. 基于xml 全类名 构造注入

<bean id="person" class="top.arioso.spring.beans.Person">
        <constructor-arg type="java.lang.String">
            <value>John</value>
        </constructor-arg>
        <constructor-arg value="America" index="3"><constructor>
        <constructor-arg value="123456" type="int"><constructor>
        <constructor-arg value="man" typ><constructor>
        <property name="id">
            <value>123456</value>
        </property>
        <property name="age" value="18"></property>
    </bean>
    要求必须有带参构造
    根据value值匹配构造器,匹配不到就匹配下一个
    可以用index属性指定带参构造器第几个参数
    可以用type属性指定构造函数参数类型的匹配
    value属性可用子节点value替代      

3. 基于xml 通过工厂配置

  (1) 静态工厂方法配置

<bean id="car" class="top.arioso.spring.factory.staticCarFactory" factory-method="getCar">
        <constructor-arg value="BMW"></constructor-arg>
    </bean>
    class:工厂方法全类名
    factory-method:要调用工厂方法名
    若需要传递参数,使用constructor-arg传值      

  (2)实例工厂方法配置

<bean id="carFactory" class="top.arioso.spring.beans.carFactory"></bean>
    <bean id="car" factory-bean="carFactory" factory-method="getCar">
        <constructor-arg value="BMW"></constructor-arg>
    </bean>
    carFactory:工厂的实例
    factory-bean: 指向工厂的实例
    factory-method:要调用工厂方法名
    若需要传递参数,使用constructor-arg传值      

  (3)通过FactoryBean配置

 spring框架自身提供的,它需要实现FactoryBean接口,实现代码就必须写在getObject()方法中。

//java代码
    public class SpringFactory implements FactoryBean<Calendar>{
    public SpringFactory() {
    System.out.println("我是一个spring工厂类");
    }

    public Calendar getObject() throws Exception {
        return Calendar.getInstance();
    }

    public Class<?> getObjectType() {
        return Calendar.class;
    }

    public boolean isSingleton() {
        return false;
    }      
//配置文件
    <bean id="cal" class="springfactory.SpringFactory"/>
    该配置返回的实例是SpringFactory的getObject方法返回的实例。      

4. spring配置Bean注入

① 配置字面值

    可通过value属性或<value>标签属性注入,

    若字面值包含特殊字符,使用<![CDATA[]]>包裹

    spring将属性的空参数当空String,下面给email属性设置了空的String值("")

 

<bean id="nullBean" class="top.arioso.spring.NullBean">
        <property name="email" value="" />
    </bean>
   如果要注入null值,可以使用<null />
    <bean id="exampleBean" class="top.arioso.spring.NullBean">
        <property name="email">
            <null />
        </property>
    </bean>
      

② Bean之间的引用

<bean id="dog" class="top.arioso.hello.Dog"/>
    <bean id="user" class="top.arioso.hello.User">
        <property name="name" value="tony"/>
        <property name="dog" ref="dog"></property>
    </bean>      

③ List属性(set同理)

<bean id="user" class="top.arioso.hello.User">
        <property name="list">
            <list>
                <value>北京</value>
                <value>上海</value>
                <value>广州</value>
                <ref bean="dog"/>
            </list>
        </property>
    </bean>      

④ map属性

<bean id="user" class="top.arioso.hello.User">
        <property name="map">
            <map>
                <entry key="bj" value="北京"/>
                <entry key="sh" value="上海"/>
            </map>
        </property>
    </bean>      

⑤ Properties属性

<bean id="user" class="top.arioso.hello.User">
        <property name="dbParams">
            <props>
                <prop key="username">root</prop>
                <prop key="password">root</prop>
            </props>
        </property>
    </bean>      

⑥ 独立的集合Bean

<util:list id="computerList">
        <ref bean="computer"/>
        <bean class="top.arioso.spring.collection.ComputerList">
            <constructor-arg value="hp"></constructor-arg>
            <constructor-arg value="dell"></constructor-arg>
            <constructor-arg value="acer"></constructor-arg>
        </bean>
    </util:list>
    <bean id="User" class="top.arioso.spring.User">
        <property name="id" value="2018310"></property>
        <property name="name" value="Tom"></property>
        <property name="computers" value="computerList"></property>
    </bean>      

⑦ 使用p命名空间

<bean id="computer" class="top.arioso.spring.Computer">
        <p:brand="dell" p-cpu="i7-7700" p-price="7900">
    </bean>
    首先需要导入命名空间      

5. 基于注解配置Bean

① 注解依赖aop包,要导入aop包。

② Spring 能够从 classpath 下自动扫描(需要配置 context:component-scan )具有特定注解的组件。

    特定的组件包括:

    @Component:基本注解,标识一个受Spring管理的组件。

    @Repository:标识持久层组件。

    @Service:标识业务层组件。

    @Controller:标识控制层组件。

     Spring 对扫描到的组件有默认的命名规则:使用非限定类名,第一个字母小写 (也可以使用value属性指定组件的名称)。

③ 配置<context:component-scan>

<context:component-scan
        base-package="top.arioso.spring.annotation"
        resource-pattern="service/*.class">
    </context:component-scan>
    base-package 属性指定Spring扫描的包,Spring将扫描该包及其所有子包,如有多个包,使用逗号隔开。
    可以使用 resource-pattern 来过滤特定的类。
    
    
    <context:exclude-filter>:指定扫描排除哪些类
    需设置use-default-filter为false
    //只扫描有Service注解的类
    <context:component-scan resource-pattern="controller/*.class"
        base-package="top.arioso.spring.annotation"
        use-default-filters="false">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service">
    </context:component-scan>
    
    //排除扫描实现了UserRepository的类
    <context:component-scan resource-pattern="controller/*.class"
        base-package="top.arioso.spring.annotation"
        use-default-filters="false">
        <context:exclude-filter type="assignable" expression="top.arioso.repository.UserRepository">
    </context:component-scan>
    
    
    
    <context:include-filter>:指定扫描包含哪些类
    //排除扫描有Service注解的类
    <context:component-scan resource-pattern="controller/*.class"
        base-package="top.arioso.spring.annotation"
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Service">
    </context:component-scan>
    
    //只扫描实现了UserRepository的类
    <context:component-scan resource-pattern="controller/*.class"
        base-package="top.arioso.spring.annotation"
        <context:include-filter type="assignable" expression="top.arioso.repository.UserRepository">
    </context:component-scan>      

6. 使用 @Autowired 注解自动装配Bean

    可以再字段、setter方法、构造器上面使用

    默认情况下,当使用 @Autowired 注解的属性,如果在IOC容器中找不到匹配的Bean来装配属性时,会抛出异常。可以使用 required=false 设置某一属性不被设置(即IOC容器不配置匹配的Bean)。

    使用@Autowired注解的属性,当 IOC 容器中存在多个类型匹配的 Bean 时,默认情况下会匹配与属性相同名称的 Bean,若匹配不到则抛出异常。也可以使用 @Qualifier(“Bean名称”) 注解指定注入的Bean。

     @Autowired也可以用在数组上,Spring会将所有匹配的Bean自动装配进数组。

     @Autowired也可以用在集合上,Spring会判断该集合的类型,然后自动装配所有类型兼容的Bean。

     @Autowired也可以用在Map上,若key为String类型,Spring将Bean的名称作为key,Bean本身作为值自动装配所有类型兼容的的Bean。

     也可以使用 @Resource 或 @Inject 自动装配Bean,功能与 @Autowired 类似,建议使用@Autowired注解。