美文网首页
Spring的IoC容器

Spring的IoC容器

作者: luoxn28 | 来源:发表于2017-06-22 07:41 被阅读0次

    Spring是一个轻量级的Java开发框架,其提供的两大基础功能为IoC和AOP,其中IoC为依赖反转(Inversion of Control)。IOC容器的基本理念就是“为别人服务”,那为别人服务什么呢?其中最重要就是业务对象的构建管理和业务对象之间的依赖绑定

    • 业务对象的构建管理:业务场景中,无需关心业务对象如何创建、如何管理,在需要时只需获取即可。业务对象的构建管理交给IoC容器,避免这部分代码对业务逻辑的侵染。
    • 业务对象之间的依赖绑定:IoC容器需要先了解业务对象之间的依赖关系,这样依据之前业务对象的构建管理就可以对外提供IoC服务,保证每个业务对象在使用时处于就绪状态。

    IoC容器管理业务对象,首先需要知道业务对象之间的依赖关系,以下有几种方式告诉IoC容器其管理的对象之间的绑定关系:

    • 可以通过简单的文本方式记录被注入对象和其依赖对象的对应关系。
    • 使用描述性更强的XML文件格式记录对象之间的对应关系。
    • 还可以通过编写代码的方式(调用IoC容器提供的对应API)设置对象之间的关系。
    • ...

    注意:不管是什么方式来告知IoC容器对象之间的绑定关系,最终都是通过编码方式(调用IOC提供的API)来将这些信息"写入"到IoC容器中的。

    2种基本的容器类型

    Spring的IoC容器提供两种基本的容器类型:BeanFactory和ApplicationContext。

    • BeanFactory:基础类型IoC容器,提供基本的容器服务,如果没有特殊指定,采用延迟初始化策略,也就是当客户端需要容器中某个对象时,才对该受管理的对象初始化及其依赖注入操作。所以,相对来说,BeanFactory容器启动较快,所需资源有限,对于资源有限,并且功能要求不严格的场景,使用BeanFactory容器是比较合适的。
    • ApplicationContext:ApplicationContext是在BeanFactory基础之上构建的,是一个比较高级的容器,除了拥有BeanFactory的全部功能外,也提供其他高级特性,比如事件发布、国际化信息支持等。ApplicationContext所管理的对象,默认ApplicationContext启动之后全部初始化并绑定完成,所以其启动较慢,占用资源较多。在系统资源充足,并需要提供较多功能的使用场景,ApplicationContext是一个不错的选择。

    依赖注入的3种方式

    • 构造方法注入:调用被注入对象的构造方然注入,优点是对象在构造完成就进入了就绪状态。
    • 属性注入:调用被注入对象的setter/getter方法。
    • 接口注入:现在不提倡的一种方式,因为它强制被注入对象实现不必要的接口,带有侵入性。

    spring的bean配置(XML配置方式)

    属性注入即通过 setter 方法注入Bean 的属性值或依赖的对象,使用 <property> 元素, 使用 name 属性指定 Bean 的属性名称,value 属性或 <value> 子节点指定属性值,属性注入是实际应用中最常用的注入方式。属性注入Bean类须有一个默认的构造方法。

    <!-- Hello类中有一个String类型的msg属性 -->
    <bean id="hello" class="com.luoxn28.Hello">
        <property name="msg" value="luoxn28"/>
    </bean>
    

    通过构造方法注入Bean 的属性值或依赖的对象,它保证了 Bean 实例在实例化后就可以使用,构造器注入在 <constructor-arg> 元素里声明属性。

    <bean id="msg" class="java.lang.String">
        <constructor-arg value="string"/>
    </bean>
    
    <!-- 按照索引匹配入参 -->
    <bean id="car" class="com.luoxn28.Car">
        <constructor-arg value="比亚迪" index="0"/>
        <constructor-arg value="中国制造" index="1"/>
        <constructor-arg value="200000" index="2"/>
    </bean>
    <!-- 按照类型匹配入参 -->
    <bean id="car2" class="com.luoxn28.Car">
        <constructor-arg value="比亚迪" type="java.lang.String">
        <constructor-arg value="中国制造" type="java.lang.String"/>
        <constructor-arg value="200000" type="double"/>
    </bean>
    

    多个Bean依赖配置,需在Bean配置中指定对Bean的引用。既可以使用"ref"属性配置,也可以直接在属性里包含Bean的配置,即内部Bean。内部Bean只能在当前定义处使用,貌似其他地方也没法使用哈 :)

    <bean id="msg" class="java.lang.String">
        <constructor-arg value="luoxn28"/>
    </bean>
    
    <!-- Hello类中有一个String类型的msg属性 -->
    <bean id="hello" class="com.luoxn28.Hello">
        <property name="msg" ref="msg"/>
    </bean>
    
    <!-- Hello类中有一个String类型的msg属性 -->
    <bean id="hello" class="com.luoxn28.Hello">
        <property name="msg">
            <bean class="java.lang.String">
                <constructor-arg value="luoxn28"/>
            </bean>
        </property>
    </bean>
    

    如果Bean属性是集合/容器类型,则通过<list>/<set>/<map>来配置。

    <!-- CollectionClass类有3个属性,List<String> list、Set<String> set、Map<String, String> map-->
    <bean id="collectionClass" class="com.luoxn28.CollectionClass">
        <property name="list">
            <list>
                <value>luoxn28</value>
                <value>luoxn29</value>
                <value>luoxn30</value>
            </list>
        </property>
        <property name="set">
            <set>
                <value>luoxn28</value>
                <value>luoxn29</value>
                <value>luoxn30</value>
            </set>
        </property>
        <property name="map">
            <map>
                <entry key="str1" value="luoxn28"/>
                <entry key="str2"><value>luoxn29</value></entry>
                <entry key="str3"><value>luoxn30</value></entry>
            </map>
        </property>
    </bean>
    

    Bean的作用域

    Spring最初提供ean的两种scope类型:singleton和prototype,在发布2.0之后,新增了request、session和global session类型,不过这3种新增的只能用在Web应用中。可以通过bean属性scope来指定bean的scope类型,如果是singleton类型的话,在用户获取该bean之后,容器还是会接管该bean的生命周期;如果是prototype的话,在用户获取该bean之后,容器就不接管该bean了,也就是容器每次会创建一个新的bean对象返回给用户。

    <!-- Hello对象每次获取都会新建 -->
    <bean id="hello" class="com.luoxn28.Hello" scope="prototype">
        <property name="msg" value="luoxn28"/>
    </bean>
    

    通过静态方法创建bean

    调用静态工厂方法创建 Bean是将对象创建的过程封装到静态方法中,当用户需要对象时,只需要简单地调用静态方法,而不同关心创建对象的细节。要声明通过静态方法创建的 Bean, 需要在 Bean 的 class 属性里指定拥有该工厂的方法的类, 同时在 factory-method 属性里指定工厂方法的名称. 最后, 使用 <constrctor-arg> 元素为该方法传递方法参数。

    public static Hello createHello() {
        return new Hello();
    }
    
    <bean id="hello" class="com.luoxn28.Hello" factory-method="createHello">
    </bean>
    

    BeanFactory

    Spring 中有两种类型的 Bean, 一种是普通Bean,另一种是工厂Bean,即FactoryBean。工厂 Bean 跟普通Bean不同,,其返回的对象不是指定类的一个实例,其返回的是该工厂 Bean 的 getObject 方法所返回的对象
    FactoryBean接口源码如下所示:

    public interface FactoryBean<T> {
        // 返回的实例
        T getObject() throws Exception;
        // 返回的类型
        Class<?> getObjectType();
        // 是否为单例
        boolean isSingleton();
    }
    

    BeanFactory使用示例:

    public class Hello {
        private String name;
        private int age;
        // set/get方法
    }
    
    public class HelloBeanFactory implements FactoryBean<Hello> {
        @Override
        public Hello getObject() throws Exception {
            Hello hello = new Hello();
    
            hello.setName("luoxn28");
            hello.setAge(23);
            return hello;
        }
    
        @Override
        public Class<?> getObjectType() {
            return Hello.class;
        }
    
        @Override
        public boolean isSingleton() {
            return true;
        }
    }
    

    然后在applicationContext.xml中配置如下,就可以获取Hello类实例了。

    <bean id="helloBean" class="com.luoxn28.hello.HelloBeanFactory">
    </bean>
    
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    
        Hello hello = context.getBean("helloBean", Hello.class);
        System.out.println(hello);
    }
    

    参考资料:

    1. Spring的IoC容器
    2. 《Spring揭秘》IOC章节

    相关文章

      网友评论

          本文标题:Spring的IoC容器

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