zoukankan      html  css  js  c++  java
  • Spring之IOC

    一、Spring的IoC容器

    IOC概念:控制反转其实是控制权的转移,被调用类的创建原本由调用类进行管理,当前管理权转移到由Spring容器进行管理。
    Spring 提供了两种 IoC 容器,分别为 BeanFactoryApplicationContext
    Spring 容器是 Spring 框架的核心。容器将创建对象,把它们连接在一起,配置它们,并管理他们的整个生命周期从创建到销毁。Spring 容器使用依赖注入(DI)来管理组成一个应用程序的组件。这些对象被称为 Spring Beans。

    • BeanFactory 是基础类型的 IoC 容器,它由 org.springframework.beans.facytory.BeanFactory接口定义,并提供了完整的 IoC 服务支持。BeanFactory 和相关的接口,比如BeanFactoryAware、DisposableBean、InitializingBean,仍旧保留在 Spring 中,主要目的是向后兼容已经存在的和那些 Spring 整合在一起的第三方框架。
      简单来说,BeanFactory 就是一个管理 Bean 的工厂,它主要负责初始化各种 Bean,并调用它们的生命周期方法。 BeanFactory 接口有多个实现类,最常见的是 org.springframework.beans.factory.xml.XmlBeanFactory,它是根据 XML 配置文件中的定义装配 Bean 的。·
    • ApplicationContext 是 BeanFactory 的子接口,也被称为应用上下文。该接口的全路径为 org.springframework.context.ApplicationContext,它不仅提供了 BeanFactory 的所有功能,还添加了对 i18n(国际化)、资源访问、事件传播等方面的良好支持。
      通常在 Java 项目中,会采用通过 ClassPathXmlApplicationContext 类实例化 ApplicationContext 容器的方式,
      而在 Web 项目中,ApplicationContext 容器的实例化工作会交由 Web 服务器完成。Web 服务器实例化 ApplicationContext 容器通常使用基于 ContextLoaderListener 实现的方式,它只需要在 web.xml 中添加如下代码:
    <!--指定Spring配置文件的位置,有多个配置文件时,以逗号分隔-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <!--spring将加载spring目录下的applicationContext.xml文件-->
        <param-value>
            classpath:spring/applicationContext.xml
        </param-value>
    </context-param>
    <!--指定以ContextLoaderListener方式启动Spring容器-->
    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>

    二、Spring Bean

    Spring 容器可以被看作一个大工厂,而 Spring 容器中的 Bean 就相当于该工厂的产品。如果希望这个大工厂能够生产和管理 Bean,这时则需要告诉容器需要哪些 Bean,以及需要以何种方式将这些 Bean 装配到一起。

    1. Spring Bean配置

    Spring 的配置文件名称是可以自定义的,通常情况下,都会将配置文件命名为 applicationContext.xml;

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
    
        <!-- 由 Spring容器创建该类的实例对象 -->
        <bean id="personDao" class="com.mengma.ioc.PersonDaoImpl" />
    
        <bean id="personService" class="com.mengma.ioc.PersonServiceImpl">
            <!-- 将personDao实例注入personService实例中 -->
            <property name="personDao" ref="personDao"/>
        </bean>
    </beans>

    约束配置:beans的属性是Sring的约束配置;
    xmlns="http://www.springframework.org/schema/beans", 默认命名空间:它没有空间名,用于Spring Bean的定义;
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance", xsi命名空间:这个命名空间用于为每个文档中命名空间指定相应的Schema样式文件,是标准组织定义的标准命名空间。

    创建实例:Spring 容器中创建一个 id 为 personDao 的 bean 实例,其中 id 表示文件中的唯一标识符,class 属性表示指定需要实例化 Bean 的实全限定类名(包名+类名)

    属性名称 描述
    id 是一个 Bean 的唯一标识符,Spring 容器对 Bean 的配置和管理都通过该属性完成
    name Spring 容器同样可以通过此属性对容器中的 Bean 进行配置和管理,name 属性中可以为 Bean 指定多个名称,每个名称之间用逗号或分号隔开
    class 该属性指定了 Bean 的具体实现类,它必须是一个完整的类名,使用类的全限定名
    scope 用于设定 Bean 实例的作用域,其属性值有 singleton(单例)、prototype(原型)、request、session 和 global Session。其默认值是 singleton
    constructor-arg 元素的子元素,可以使用此元素传入构造参数进行实例化。该元素的 index 属性指定构造参数的序号(从 0 开始),type 属性指定构造参数的类型
    property 元素的子元素,用于调用 Bean 实例中的 Set 方法完成属性赋值,从而完成依赖注入。该元素的 name 属性指定 Bean 实例中的相应属性名
    ref 和 等元素的子元索,该元素中的 bean 属性用于指定对 Bean 工厂中某个 Bean 实例的引用
    value 和 等元素的子元素,用于直接指定一个常量值
    list 用于封装 List 或数组类型的依赖注入
    set 用于封装 Set 类型属性的依赖注入
    map 用于封装 Map 类型属性的依赖注入
    entry 元素的子元素,用于设置一个键值对。其 key 属性指定字符串类型的键值,ref 或 value 子元素指定其值

    2. Spring Bean的实例化

    在面向对象的程序中,要想调用某个类的成员方法,就需要先实例化该类的对象。在 Spring 中,实例化 Bean 有三种方式,分别是构造器实例化、静态工厂方式实例化和实例工厂方式实例化。

    构造器实例化是指 Spring 容器通过 Bean 对应的类中默认的构造函数实例化 Bean。大多数情况下常用的实例化方式。
    其他两种不常用,暂时不作为重点,参考:http://c.biancheng.net/view/4256.html

    3. Spring Bean的作用域

    当在 Spring 中定义一个 bean 时,你必须声明该 bean 的作用域的选项。
    例如,为了强制 Spring 在每次需要时都产生一个新的 bean 实例,你应该声明 bean 的作用域的属性为 prototype。同理,如果你想让 Spring 在每次需要时都返回同一个bean实例,你应该声明 bean 的作用域的属性为 singleton

    Spring 框架支持以下五个作用域,分别为singleton、prototype、request、session和global session,5种作用域说明如下所示,

    作用域 描述
    singleton 在spring IoC容器仅存在一个Bean实例,Bean以单例方式存在,默认值
    prototype 每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行newXxxBean()
    request 每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境
    session 同一个HTTP Session共享一个Bean,不同Session使用不同的Bean,仅适用于WebApplicationContext环境
    global-session 一般用于Portlet应用环境,该运用域仅适用于WebApplicationContext环境
    3.1、singleton
    <bean id="book" class="com.dreamice.scope.Book" scope="singleton"/>
    System.out.println(applicationContext.getBean("book"));
    System.out.println(applicationContext.getBean("book"));

    输出:
    com.dreamice.scope.Book@43814d18
    com.dreamice.scope.Book@43814d18

    3.2、prototype
    <bean id="book" class="com.dreamice.scope.Book" scope="prototype"/>
    System.out.println(applicationContext.getBean("book"));
    System.out.println(applicationContext.getBean("book"));

    输出:
    com.dreamice.scope.Book@2758fe70
    com.dreamice.scope.Book@1f36e637

    4、Spring Bean的生命周期

    http://c.biancheng.net/view/4261.html

    三、Spring的依赖注入(DI)和装配

    依赖注入(Dependency Injection,DI)和控制反转含义相同,它们是从两个角度描述的同一个概念。
    依赖注入主要有两种实现方式,分别是属性 setter 注入和构造方法注入;

    1、属性 setter 注入

    // 定义接口声明
    private PersonDao personDao;
    // 提供set()方法,用于依赖注入
    public void setPersonDao(PersonDao personDao) {
        this.personDao = personDao;
    }

    配置文件中,实例注入到实例<property name="personDao" ref="personDao"/>必须有,不然会报NPE;所以说setter要和配置文件同步一致才可以。

    2、构造方法注入

    3、注入和装配的区别

    Bean 的装配可以理解为依赖关系注入,Bean 的装配方式也就是 Bean 的依赖注入方式。Spring 容器支持多种形式的 Bean 的装配方式,如基于 XML 的 Bean 装配、基于 Annotation 的 Bean 装配和自动装配等。(http://c.biancheng.net/view/4264.html)

    依赖注入的本质就是装配,装配是依赖注入的具体行为。(https://blog.csdn.net/u012843873/article/details/52399206)

    可以理解为:注入就是装配

    4、基于Annotation装配Bean

    主要注解有:

    注解 作用
    @Component 可以使用此注解描述 Spring 中的 Bean,但它是一个泛化的概念,仅仅表示一个组件(Bean),并且可以作用在任何层次。使用时只需将该注解标注在相应类上即可。
    @Repository 用于将数据访问层(DAO层)的类标识为 Spring 中的 Bean,其功能与 @Component 相同。
    @Service 通常作用在业务层(Service 层),用于将业务层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。
    @Controller 通常作用在控制层(如 Struts2 的 Action),用于将控制层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。
    @Autowired 用于对 Bean 的属性变量、属性的 Set 方法及构造函数进行标注,配合对应的注解处理器完成 Bean 的自动配置工作。默认按照 Bean 的类型进行装配。
    @Resource 其作用与 Autowired 一样。其区别在于 @Autowired 默认按照 Bean 类型装配,而 @Resource 默认按照 Bean 实例名称进行装配;@Resource 中有两个重要属性:name 和 type。Spring 将 name 属性解析为 Bean 实例名称,type 属性解析为 Bean 实例类型。如果指定 name 属性,则按实例名称进行装配;如果指定 type 属性,则按 Bean 类型进行装配。如果都不指定,则先按 Bean 实例名称装配,如果不能匹配,则再按照 Bean 类型进行装配;如果都无法匹配,则抛出 NoSuchBeanDefinitionException 异常。
    @Qualifier 与 @Autowired 注解配合使用,会将默认的按 Bean 类型装配修改为按 Bean 的实例名称装配,Bean 的实例名称由 @Qualifier 注解的参数指定。

    不仅是@Resource,使用@Autoware注解也是不需要set和get方法的。因为spring在实例化对象时,是通过java的反射机制注入实例。(https://q.cnblogs.com/q/80710/

    4.1、@Resource的使用
    @Service("bookService")
    public class BookServiceImpl implements BookService {
        @Resource(name = "bookDao")
        private BookDao bookDao;
    
        @Override
        public void add() {
            bookDao.add();
        }
    }

    配置文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:p="http://www.springframework.org/schema/p"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    
        <context:component-scan base-package="com.dreamice"/>
    </beans>

    @Autowired和@Qualifier的使用参考:https://www.cnblogs.com/caoyc/p/5626365.html

    5、Spring Beans 自动装配

    四、实际项目问题

    问题1、使用@Autowired注入后报错为null

    • 调用类B在使用自动注入被调用类C时,必须保证自身是受Spring容器进行管理的,因此需要在类上添加@Service、@Component等注解,否则实例C使用时会为null;
    • 调用类A的类也要保证是通过@Autowired的方式注入B,即使通过new的方式实例化B,也要添加@Autowired,否则B类不再受Spring容器管理。
    @Controller
    public class A}{
        //自动注入
        @Autowired
        private B b;
        //项目中有使用new的方式,这种情况添加@Autowired,才能保证实例c不为null
        B b = new B();
    }
    
    @Service
    public class B{
        @Autowired
        private C c;
        public void test(){
            c.test();
        }
    }
    
    @Repositroy
    public class C}{
        public void test(){
    
        }
    }

    参考资料:

    1、C语言中文网-Java Spring框架入门教程
    2、慕课网-Spring框架小白的蜕变
    3、W3Cschool-Spring 教程
    4、依赖注入与自动装配

  • 相关阅读:
    C++11 lambda表达式(lambda expression)
    win 10 relog.exe 下载地址
    检测闩锁/自旋锁争用
    关于sql 锁和并发的一些记录
    FAST number_rows 意义解释
    网站实施SEO的步骤
    搜索引擎高级搜索指令浅析
    关于遇到高并发时候的一些总结
    Autofac 设置方法拦截器的两种方式
    C# MVC 进入Action 方法之后怎么使用MVC参数验证模型
  • 原文地址:https://www.cnblogs.com/Dreamice/p/11883847.html
Copyright © 2011-2022 走看看