zoukankan      html  css  js  c++  java
  • spring(四):IoC

    IoC—Inversion of Control,即控制反转

    IoC意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。

    理解IoC的关键:“谁控制谁,控制什么,为何是反转,哪些方面反转了”:

    谁控制谁,控制什么:传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由IoC容器来控制对象的创建;

    谁控制谁?IoC 容器控制对象;

    控制什么?控制外部资源获取。

    为何是反转,哪些方面反转了:传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象;而IoC则是由容器来帮忙创建及注入依赖对象;

    为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;

    哪些方面反转了?依赖对象的获取被反转了。

    IoC很好的体现了面向对象设计法则之一—— 好莱坞法则:“别找我们,我们找你”

    DI—Dependency Injection,即“依赖注入”

    是组件之间依赖关系由容器在运行期决定,即由容器动态的将某个依赖关系注入到组件之中。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,而不需要关心具体的资源来自何处,由谁实现。

    理解DI的关键是:“谁依赖谁,为什么需要依赖,谁注入谁,注入了什么”:

    谁依赖于谁:应用程序依赖于IoC容器;Bean依赖IoC容器;依赖指的是Bean之间的依赖关系

    为什么需要依赖:应用程序需要IoC容器来提供对象需要的外部资源;Bean需要IoC容器来创建

    谁注入谁:IoC容器注入应用程序某个对象,应用程序依赖的对象;

    ●注入了什么:注入某个对象所需要的外部资源(包括对象、资源、常量数据)。

    Spring IoC容器如何知道哪些是它管理的对象呢?

    Spring IoC容器通过读取配置文件中的配置元数据(BeanDefinition),通过元数据对应用中的各个对象进行实例化及装配。

    Spring与配置文件完全解耦,可以使用任何可能的方式进行配置元数据,比如注解、基于xml的、基于java文件的、基于属性文件的配置。

    由IoC容器管理的那些组成应用程序的对象我们就叫它Bean。

    在Spring中BeanFactory是IoC容器的实际代表者。ApplicationContext 接口继承了BeanFactory。简单说, BeanFactory提供了IoC容器最基本功能,而 ApplicationContext 则增加了更多支持企业级功能支持。

    public static void main(String[] args) {
        // 1、读取配置文件实例化一个IoC容器
        ApplicationContext context = new ClassPathXmlApplicationContext("hello.xml");
        // 2、从容器中获取Bean,注意此处完全“面向接口编程,而不是面向实现”
        HelloApi helloApi = context.getBean("hello", HelloApi.class);
        // 3、执行业务逻辑
        helloApi.sayHello();
     }
    

    Bean?

    本质就是一个POJO类,但具有以下限制:

    • 该类必须要有公共的无参构造器
    • 属性为private访问级别,不建议public,如private String message
    • 属性必要时通过一组setter和getter方法来访问

    作用域

    Spring 框架支持以下五个作用域,分别为singleton、prototype、request、session和global session。

    作用域 描述
    singleton Spring会缓存单例对象,在IoC容器仅存在一个Bean实例,默认值
    prototype Spring不会缓存原型对象,每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行newXxxBean()
    request 每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境
    session 同一个HTTP Session共享一个Bean,不同Session使用不同的Bean,仅适用于WebApplicationContext环境
    global-session 一般用于Portlet应用环境,该运用域仅适用于WebApplicationContext环境
    <bean id="..." class="..." scope="singleton"></bean>
    

    自定义作用域:org.springframework.beans.factory.config.Scope

    生命周期

    Bean的生命周期可以表达为:Bean的定义——Bean的初始化——Bean的使用——Bean的销毁

    初始化回调

    一、org.springframework.beans.factory.InitializingBean 接口指定一个单一的方法:

    void afterPropertiesSet() throws Exception;
    

    二、配置元数据,使用 init-method 属性来指定带有 void 无参数方法的名称:

    <bean id="exampleBean" class="examples.ExampleBean" init-method="init"/>
    

    销毁回调

    一、org.springframework.beans.factory.DisposableBean 接口指定一个单一的方法:

    void destroy() throws Exception;
    

    二、配置元数据,你使用 destroy-method 属性来指定带有 void 无参数方法的名称:

    <bean id="exampleBean" class="examples.ExampleBean" destroy-method="destroy"/>
    

    后置处理器

    允许在调用初始化方法前后对 Bean 进行额外的处理。

    是一个监听器,它可以监听容器触发的事件。将它向IoC容器注册后,容器中管理的Bean具备了接收IoC容器事件回调的能力。

    在populateBean之后的initializeBean中被调用。在Bean的初始化之前提供postProcessBeforeInitialization回调入口。在Bean的初始化之后提供postProcessAfterInitialization回调入口。

    public class InitBean implements BeanPostProcessor {
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("BeforeInitialization : " + beanName);
            return bean;  // you can return any other object as well
        }
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("AfterInitialization : " + beanName);
            return bean;  // you can return any other object as well
        }
    }
    

    Bean自身的方法:如调用 Bean 构造函数实例化 Bean,调用 Setter 设置 Bean 的属性值以及通过的 init-method 和 destroy-method 所指定的方法;

    Bean级生命周期接口方法:如 BeanNameAware、 BeanFactoryAware、 InitializingBean 和 DisposableBean,这些接口方法由 Bean 类直接实现;

    容器级生命周期接口方法:在上图中带“★” 的步骤是由 InstantiationAwareBean PostProcessor 和 BeanPostProcessor 这两个接口实现,一般称它们的实现类为“ 后处理器” 。 后处理器接口一般不由 Bean 本身实现,它们独立于 Bean,实现类以容器附加装置的形式注册到 Spring 容器中并通过接口反射为 Spring 容器预先识别。当Spring 容器创建任何 Bean 的时候,这些后处理器都会发生作用,所以这些后处理器的影响是全局性的。当然,用户可以通过合理地编写后处理器,让其仅对感兴趣Bean 进行加工处理

    Spring IoC容器如何实例化Bean呢?

    IoC容器需要根据Bean定义里的配置元数据使用反射机制来创建Bean。

    一、使用构造器实例化Bean

    指定必须的class属性

    <bean id="hello" class="hello.HelloApiImpl"></bean>
    

    二、使用静态工厂方式实例化Bean

    指定必须的class属性

    指定factory-method属性来指定实例化Bean的方法

    <bean id="hello" class="hello.HelloApiStaticFactory" factory-method="newInstance"></bean>
    

    三、使用实例工厂方法实例化Bean

    不能指定class属性

    使用factory-bean属性指定工厂Bean

    使用factory-method属性指定实例化Bean的方法

    <!—定义实例工厂Bean -->  
    <bean id="beanInstanceFactory" class="hello.HelloApiInstanceFactory"/>  
    <!—使用实例工厂Bean创建Bean -->  
    <bean id="hello" factory-bean="beanInstanceFactory" factory-method="newInstance"></bean>
    

    Spring IoC容器如何注入Bean的依赖资源?

    在基于构造函数注入中,我们使用的是〈bean〉标签中的〈constructor-arg〉元素;

    而在基于设值函数的注入中,我们使用的是〈bean〉标签中的〈property〉元素。

    构造器注入:

    实例化Bean时,通过在Bean定义中指定构造器参数进行注入依赖,包括实例工厂方法参数注入依赖,但静态工厂方法参数不允许注入依赖;

    • 根据参数索引注入
    <constructor-arg index="0" value="Hello World!"/>
    

    构造函数的参数在 bean 定义中的顺序就是把这些参数提供给适当的构造函数的顺序。

    最好的传递构造函数参数的方式,是使用 index 属性来显式的指定构造函数参数的索引。

    • 根据参数类型注入
    <constructor-arg type="java.lang.String" value="Hello World!"/>
    
    • 根据参数名注入:在构造器上使用@ConstructorProperties注解来指定参数名。只对构造器实例化Bean方式起作用,而对工厂不起作用。
    <constructor-arg name="message" value="Hello World!"/>
    

    setter注入

    实例化Bean后,通过调用Bean类的setter方法进行注入依赖;

    • 注入常量:
    <property name="message" value="Hello World!"/>
    
    <property name="message"><value>Hello World!</value></property>
    
    • 注入Bean ID:
    <property name="id"><idref bean="bean1"/></property>
    
    • 注入集合(Collection、Set、List):
    <property name="values">
        <list value-type="可选" merge="可选">
            <value>1</value>
            <value>2</value>
            <value>3</value>
        </list>
    </property>  
    
    <property name="values"><set value-type="同上">...</set></property>
    
    • 注入数组:

    一维:

    <property name="id">
        <array>...</array>
    </property>  
    

    二维:

    <property name="id">
        <array>
            <array>...</array>
            <array>...</array>
        </array>
    </property>  
    
    • 注入字典:
    <property name="id">
        <map>
            <entry key="" value=""/>
            <entry key="" value=""/>
        </map>
    </property>  
    
    • 注入Properties:
    <property name="id">
        <props value-type="无用,就是String">
            <prop key="">value</prop>
            <prop key="">value</prop>
        </map>
    </property>  
    
    • 注入依赖Bean:

    如果你想要向一个对象传递一个引用,你需要使用标签的 ref 属性,如果你想要直接传递值,那么你应该使用如上所示的 value 属性。

    一般:

    <constructor-arg index="0" ref="bean1"/>
    
    <property name="helloApi" ref="bean1"/>
    

    高级:

    <ref local=""/>
    
    <ref parent=""/>
    
    <!-- sources/chapter3/parentBeanInject.xml表示父容器配置-->
    <!--注意此处可能子容器也定义一个该Bean-->
    <bean id="helloApi" class="cn.HelloImpl4">  
        <property name="message" value="Hello Parent!"/>
    </bean>
    
    <!-- sources/chapter3/localBeanInject.xml表示当前容器配置-->
    <!-- 注意父容器中也定义了id 为 helloApi的Bean -->
    <bean id="helloApi" class="cn.HelloImpl4">
        <property name="message" value="Hello Local!"/>  
    </bean>  
    <!-- 通过local注入 -->
    <bean id="bean1" class="cn.bean.HelloApiDecorator">
        <constructor-arg index="0"><ref local="helloApi"/></constructor-arg>
    </bean>
    <!-- 通过parent注入 -->
    <bean id="bean2" class="cn.bean.HelloApiDecorator">
        <property name="helloApi"><ref parent="helloApi"/></property>
    </bean>
    
    • 注入内部Bean:
    <bean id="bean" class="cn.bean.HelloApiDecorator">
        <property name="helloApi">
            <bean id="即便指定也没有用,是匿名的,对外部不可见" class="cn.hello.HelloImpl"/>
        </property>  
    </bean>
    
    • 处理null值:
    <property name=""><null/></property>
    

    Spring Bean自动装配?(不建议用

    在 XML 配置文件中 beans 的 auto-wire 属性设置为 byName。然后,它尝试将它的属性与配置文件中定义为相同名称的 beans 进行匹配和连接。

    在 XML 配置文件中 beans 的 autowire 属性设置为 byType。然后,如果它的 type 恰好与配置文件中 beans 名称中的一个相匹配,它将尝试匹配和连接它的属性。

    在 XML 配置文件中 beans 的 autowire 属性设置为 constructor。然后,它尝试把它的构造函数的参数与配置文件中 beans 名称中的一个进行匹配和连线。

  • 相关阅读:
    Chap5:操作文件和目录[The Linux Command Line]
    ABC3
    ABC2
    ABC
    Spring MVC / Boot
    Usefull Resources
    [ Learning ] Design Pattens
    [ Learning ] Spring Resources
    URL Resources
    [ Windows BAT Script ] BAT 脚本获取windows权限
  • 原文地址:https://www.cnblogs.com/angelica-duhurica/p/11188085.html
Copyright © 2011-2022 走看看