• Spring核心容器


    一. IOC和DI基础


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

      所谓依赖倒置,就是把原本的高层建筑依赖底层建筑“倒置”过来,变成底层建筑依赖高层建筑。高层建筑决定需要什么,底层去实现这样的需求,但是高层并不用管底层是怎么实现的。这样就不会出现前面的“牵一发动全身”的情况。
      而控制反转就是把传统程序中需要实现对象的创建、代码的依赖,反转给一个专门的"第三方"即容器来实现,即将创建和查找依赖对象的控制权交给容器,由容器将对象进行组合注入,实现对象与对象的松耦合,便于功能的复用,使程序的体系结构更灵活。

      

      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. 使用注解自动装配Bean

    ①Autowired自动注入

      @Autowired可以在字段、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 类似,一般使用@Resource和@Autowired,不推荐@Inject。

    ②Resource自动装配  

      @Resource与@Autowired作用类似,只不过@Autowired按ByType自动注入,Resource按ByName自动注入;

      @Resource装配顺序
      如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
      如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
      如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常
      如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配。

    ③@Qualifier注解

      Qualifier译为合格者,一般与Autowired配合使用,当有多个类实现一个借口,spring不知道绑定哪个实现类,可以用Qualifier(Bean名称或注解名) 配合@Autowired使用

    ④@Autowired与@Resource的区别

      @Resource是所属于J2EE的,而@Autowired是所属于Spring的;

      @Autowired是默认按类型(ByType)装配的,默认要依赖的对象必须存在,否则抛出异常,如果允许为null值,可以设置@Autowired(required=false),@Resource是默认按名称(ByName)装配的,如果不指定name,则把字段名当做名称寻找,找不到与该名称匹配的Bean时才会按类型寻找。但是一旦指定name,就会按名称寻找,找不到抛出异常。

     

     

  • 相关阅读:
    day6_redis模块和pipeline
    day6_hashlib模块
    18 MySQL数据导入导出方法与工具介绍之二
    【Vijos1264】神秘的咒语
    【Vijos1180】选课
    【vijos1234】口袋的天空
    【vijos1790】拓扑编号
    【WC2008】【BZOJ1271】秦腾与教学评估(二分,前缀和,奇偶性乱搞)
    【Baltic2003】【BZOJ1370】Gang团伙(并查集,拆点)
    【基础】二分算法学习笔记
  • 原文地址:https://www.cnblogs.com/zfinding/p/10506209.html
Copyright © 2020-2023  润新知