Spring 核心容器

核心容器

1. 核心概念

IoC

  • IoC (Inversion of Control)控制反转

    • 从主动new对象转换为由外部提供对象

    • 对象的创建控制权由程序转移到外部

  • Spring实现了此思想

    • Spring提供了一个容器,称为IoC容器,用来充当IoC思想中的外部

    • IoC容器负责对象的创建、初始化等一系列工作,被创建或被管理的对象在IoC容器中统称为Bean

DI

  • DI(Dependency Injection)依赖注入

  • 在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入

目标

  • 充分解耦

  • 使用IoC容器管理bean (IoC)

  • 在IoC容器内将有依赖关系的bean进行关系绑定(DI)

  • 最终效果:使用对象时不仅可以直接从IoC容器中获取,并且获取到的bean已经绑定了所有的依赖关系

2. 入门案例

IoC

  1. pom.xml导入依赖

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.19</version>
    </dependency>
    
  2. 创建applicationContext.xml

    <bean id="bookDao" class="com.tommychan.dao.BookDao"/>
    ...
    
    
  3. 获取Ioc容器,拿到bean

    public class App {
        public static void main(String[] args) {
            ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
            BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        }
    }
    

DI

  1. applicationContext.xml中配置service与dao的关系

    <bean id="bookDao" class="com.tommychan.dao.BookDao"/>
    
    <bean id="bookService" class="com.tommychan.service.impl.BookServiceImpl">
            <!--
                name 表示配置哪一个具体的属性
                ref 表示参照哪一个容器里已经配置了的 bean
            -->
        <property name="bookDao" ref="bookDao"/>
    </bean>
    
  2. 在com.tommychan.service.impl.BookServiceImpl中提供dao的setter方法

3. Bean

基础配置

Bean的别名配置

  • 一个Bean可以配置多个名称

    使用name指定,用逗号、分号或空格分隔

    <bean id="bookDao" name="dao,dao1,dao2" class="com.tommychan.dao.BookDao"/>
    

Bean的作用范围

  • 使用scope

    • singleton 单例创建(默认)

    • prototype 非单例

    <bean id="bookDao" name="dao,dao1,dao2" class="com.tommychan.dao.BookDao" scope="prototype"/>
    
  • 适合交给容器进行管理的bean

    • 表现层对象 servlet

    • 业务层对象 service

    • 数据层对象 dao

    • 工具对象 utils

  • 不适合交给容器进行管理的bean

    • 封装实体的域对象

Bean的实例化

  • 使用无参构造方法实例化,若没有无参构造方法(如被覆盖)则会抛出异常BeanCreationException

  • 使用静态工厂

    <bean id="bookDao" class="com.tommychan.factory.BookDaoFactory" factory-method="getBookDao"/>
    
  • 实例工厂

    • 方式一 (比较冗余,Spring针对此进行改良,见方法二)
    <bean id="bookFactory" class="com.tommychan.factory.BookDaoFactory"/> <!-- 先配置Factory bean  配合使用 实际无意义-->
    <bean id="bookDao" factory-bean="bookFactory" factory-method="getBookDao"/>
    
    • 方法二(Spring改良后)
    1. 直接创建BookDaoFactoryBean对象
    public class BookDaoFactoryBean implements FactoryBean<BookDao> {
    
        /**
         * 代替原始实例工厂创建对象的方法
         * @return 对象
         * @throws Exception 异常
         */
        @Override
        public BookDao getObject() throws Exception {
            return new BookDaoImpl();
        }
    
        @Override
        public Class<?> getObjectType() {
            return BookDao.class;
        }
        
        /**
         * 控制单例创建
         * @return true 单例
         *         false 非单例
         */
        @Override
        public boolean isSingleton() {
            return true;
        }
    }
    

    2. 配置

    <bean id="bookDao" class="com.tommychan.factory.BookDaoFactoryBean"/>
    

Bean的生命周期

概念
  • 生命周期:从创建到消亡的完整过程

  • bean生命周期:bean从创建到销毁的整体过程

  • bean生命周期控制:在bean创建后到销毁前做一些事情

控制bean的生命周期

方法一:使用配置文件

  • 提供控制方法

    public class BookDaoImpl implements BookDao{
        private BookDao bookDao;
    
        @Override
        public void init() {
            System.out.println("init...");
        }
    
        @Override
        public void destroy() {
            System.out.println("destroy...");
        }
    }
    
  • 配置文件指定方法

    <bean id="bookDao" class="com.tommychan.dao.impl.BookDaoImpl" init-method="init" destroy-method="destroy"/>
    

方法二:实现接口完成

  • 实现接口 InitializingBean DisposableBean

    public class BookServiceImpl implements BookService, InitializingBean, DisposableBean {
    
        private BookDao bookDao;
    
        @Override
        public void destroy() throws Exception {
            System.out.println("service destroy ...");
        }
    
        @Override
        public void afterPropertiesSet() throws Exception {
            System.out.println("service init...");
        }
    
        public void setBookDao(BookDaoImpl bookDao) {
            this.bookDao = bookDao;
        }
    }
    
bean的销毁操作
  • 容器关闭前触发bean的销毁

  • 关闭容器方法

    • 手工关闭
    ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    ctx.close();
    
    • 注册关闭钩子,在退出虚拟机前关闭容器
    ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    ctx.registerShutdownHook(); 
    

总结

  • 初始化容器

    1. 创建对象(内存分配)

    2. 执行构造方法

    3. 执行属性注入(set操作)

    4. 执行bean初始化方法

  • 使用bean

    1. 执行业务操作
  • 关闭/销毁容器

    1. 执行bean销毁方法

4. 依赖注入

前言

向一个类中传递数据的方式

  • 普通方法(set方法)

  • 构造方法

依赖注入描述了在容器中建立bean与bean之间依赖关系的过程,如果bean运行需要的是数字或字符串呢

  • 引用类型

  • 简单类型(基本数据类型与String)

依赖注入方式

  • setter注入

    • 简单类型

    • 引用类型

  • 构造器注入

    • 简单类型

    • 引用类型

setter注入

引用类型

  • bean中定义引用类型属性,并提供可访问的set方法

    public class BookServiceImpl implements BookService, InitializingBean, DisposableBean {
    
        private BookDao bookDao;
    
        public void setBookDao(BookDaoImpl bookDao) {
            this.bookDao = bookDao;
        }
    }
    
  • 配置文件中使用property标签ref属性

    <bean id="bookService" class="com.tommychan.service.impl.BookServiceImpl">
            
            <bean id="bookDao" class="com.tommychan.dao.impl.BookDaoImpl" init-method="init" destroy-method="destroy"/>
            <property name="bookDao" ref="bookDao"/>
            <!--
                name 表示配置哪一个具体的属性 -- 即 private BookDao bookDao;
                ref 表示参照哪一个容器里已经配置了的 bean 即 <bean id="bookDao" class="com.tommychan.dao.impl.BookDaoImpl" init-method="init" destroy-method="destroy"/>
            -->
    </bean>
    

简单类型

  • bean中定义简单类型属性,并提供可访问的set方法

    public class BookServiceImpl implements BookService, InitializingBean, DisposableBean {
    
        private int num;
        private String name;
    
        public void setNum(int num) {
            this.num = num;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    
  • 配置文件中使用property标签value属性

    <bean id="bookService" class="com.tommychan.service.impl.BookServiceImpl">
          <property name="name" value="hello"/>
          <property name="num" value="10"/>
    </bean>
    

构造器注入

  • bean中定义constructor

    public class BookServiceImpl implements BookService, InitializingBean, DisposableBean {
    
        private BookDao bookDao;
        private int num;
        private String name;
    
        public BookServiceImpl(BookDao bookDao, int num, String name) {
            this.bookDao = bookDao;
            this.num = num;
            this.name = name;
        }
    }
    
  • 配置文件

    <bean id="bookDao" class="com.tommychan.dao.impl.BookDaoImpl" init-method="init" destroy-method="destroy"/>
    <bean id="bookService" class="com.tommychan.service.impl.BookServiceImpl">
        <constructor-arg name="bookDao" ref="bookDao"/>
        <constructor-arg name="num" value="1"/>
        <constructor-arg name="name" value="hello"/>
        <!-- 关于参数适配 -->
        <!-- 方式一 :通过类型指定-->
        <constructor-arg type="int" value="1"/>
        <constructor-arg type="java.lang.String" value="hello"/>
        <!-- 方式二:通过index指定--->
        <constructor-arg index="1" value="1"/>
        <constructor-arg index="2" value="hello"/>
    </bean>
    

注入方式的选择

  • 强制依赖使用构造器进行,使用setter注入有概率不进行注入导致null对象出现

  • 可选依赖使用setter注入进行,灵活性强

  • Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨

  • 如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用setter注入完成可选依赖的注入

  • 实际开发过程中还要根据实际情况分析,如果受控对象没有提供setter方法就必须使用构造器注入

  • 自己开发的模块推荐使用setter注入

依赖自动装配

  • IoC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配

  • 自动装配方式

    • 按类型(常用)

    • 按名称

    • 按构造方法

    • 不启用自动装配

  • 配置文件中使用bean标签 autowire属性设置自动装配类型

    1. 提供setter方法

      public class BookServiceImpl implements BookService, InitializingBean, DisposableBean {
      
          private BookDao bookDao;
      
          public void setBookDao(BookDao bookDao) {
              this.bookDao = bookDao;
          }
      }
      
    2. 配置文件中使用autowired并指定类型

      <bean id="bookDao" class="com.tommychan.dao.impl.BookDaoImpl"/>
      <bean id="bookService" class="com.tommychan.service.impl.BookServiceImpl" autowire="byType"/>
      
      
      <bean id="bookDao" class="com.tommychan.dao.impl.BookDaoImpl" init-method="init" destroy-method="destroy"/>
      <bean id="bookService" class="com.tommychan.service.impl.BookServiceImpl" autowire="byName"/>
      
  • 自动装配用于引用类型依赖注入,不能对简单类型进行操作

  • 使用按类型装配时(byType)必须保障容器中相同类型的bean唯一,推荐使用

  • 使用按名称装配时(byName)必须保障容器中具有指定名称的bean,因变量名与配置耦合,不推荐使用

  • 自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效

5. 集合注入

  • 了解格式即可

  • 需要提供setter方法

public class BookDaoImpl implements BookDao{
    private BookDao bookDao;
    private int[] array;
    private List<String> list;
    private Set<String> set;
    private Map<String,String> map;
    private Properties properties;


    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }

    public void setArray(int[] array) {
        this.array = array;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

    public void setSet(Set<String> set) {
        this.set = set;
    }

    public void setMap(Map<String, String> map) {
        this.map = map;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }

    @Override
    public void init() {
        System.out.println(toString());
    }

    @Override
    public void destroy() {
        System.out.println("destroy...");
    }

    @Override
    public String toString() {
        return "BookDaoImpl{" +
                "bookDao=" + bookDao +"\n"+
                ", array=" + Arrays.toString(array) + "\n"+
                ", list=" + list + "\n"+
                ", set=" + set + "\n"+
                ", map=" + map + "\n"+
                ", properties=" + properties +
                '}';
    }
}
<bean id="bookDao" class="com.tommychan.dao.impl.BookDaoImpl" init-method="init" destroy-method="destroy">

        <property name="array">
            <array>
                <value>1</value>
                <value>2</value>
                <value>3</value>
            </array>
        </property>

        <property name="list">
            <list>
                <value>hello</value>
                <value>world</value>
            </list>
        </property>

        <property name="set">
            <set>
                <value>hello</value>
                <value>world</value>
            </set>
        </property>

        <property name="map">
            <map>
                <entry key="country" value="China"/>
                <entry key="city" value="Hubei"/>
            </map>
        </property>

        <property name="properties">
            <props>
                <prop key="city">Hubei</prop>
                <prop key="country">China</prop>
            </props>
        </property>
    </bean>

6. 数据源对象管理

  • 以druid数据源为例
<!--管理 DruidDataSource对象-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/spring_db"/>
    <property name="username" value="root"/>
    <property name="password" value="20020426cyh"/>
</bean>

一个问题:我们通常不会将value写死,而是使用properties文件配置

7. 加载properties文件

  1. 开启context命名空间

  2. 使用context空间加载properties文件

  3. 使用${}占位符读取properties中的属性

  • jdbc.properties
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring_db
jdbc.username=root
jdbc.password=20020426cyh
  • 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:context="http://www.springframework.org/schema/context"

       xsi:schemaLocation="
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd

       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd

       ">  
    
    <!--管理 DruidDataSource对象-->
    <!-- 1.开启context命名空间 -->
    <!--xmlns:context="http://www.springframework.org/schema/context"-->
    <!--http://www.springframework.org/schema/context-->
    <!--http://www.springframework.org/schema/context/spring-context.xsd-->
    <!-- 2.使用context空间加载properties文件 -->
    
    <!-- <context:property-placeholder location="jdbc.properties" system-properties-mode="NEVER"/> -->
    <context:property-placeholder location="classpath:*.properties" system-properties-mode="NEVER"/>
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

提示:

  • 我们通常使用 <context:property-placeholder location="classpath:*.properties" system-properties-mode="NEVER"/>同时加载当前工程中的所有properties文件

  • 对于导入的jar包和类路径,上面的方式无法加载properties文件,改为 location="classpath*:*.properties"即可

8. 容器

  • 配置文件的加载
//1.类路径加载配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//2.文件路径加载配置文件
ApplicationContext ctx1 =
        new FileSystemXmlApplicationContext("D:\\Codes\\Spring\\src\\main\\resources\\applicationContext.xml");
//3.加载多个配置文件
ApplicationContext ctx3 = new ClassPathXmlApplicationContext("bean1.xml", "bean2.xml");
  • 获取bean的方式
//1.通过名称获取bean
DataSource dataSource = (DataSource) ctx.getBean("dataSource");

//2.通过名称和类型获取
BookDao bookDao = ctx.getBean("bookDao", BookDao.class);

//3.通过类型获取
BookDao bookDao1 = ctx.getBean(BookDao.class);

  • BeanFactory是IoC容器的顶层接口,初始化BeanFactory对象时,加载的bean延迟加载

  • ApplicationContext接口是Spring容器的核心接口,初始化时bean立即加载

  • ApplicationContext接口提供基础的bean操作相关方法,通过其他接口扩展其功能

  • ApplicationContext接口常用初始化类

    • ClassPathXmlApplicationContext

    • FileSystemXmlApplicationContext&#

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring核心容器Spring框架中最核心的部分,提供了管理和组织应用程序中组件的功能。它包含了一系列的模块,如文本、图片等各种资源文件,同时提供了应用程序所需的各种组件,如BeanFactory、ApplicationContext等。 首先,Spring核心容器提供了BeanFactory接口,用于对Java对象(也即Bean)进行管理和配置的工厂。通过配置文件或注解的方式,我们可以定义Bean的属性和依赖关系,从而使用容器来获取已经创建好的Bean实例。BeanFactory接口负责创建和管理这些Bean,同时也负责销毁它们。 其次,Spring核心容器还提供了ApplicationContext接口,它是BeanFactory的子接口,提供了更多的功能。ApplicationContext可以从多种来源(比如文件系统、数据库、网络等)加载配置信息,并管理Bean的生命周期。除了BeanFactory的所有功能,ApplicationContext还支持国际化、事件发布、资源管理等更高级的功能。 另外,Spring核心容器还包括了一些辅助模块,如AOP(面向切面编程)、ORM(对象关系映射)等。这些模块可以与核心容器无缝集成,提供更强大、更灵活的功能。例如,通过AOP,我们可以在不修改原有代码的情况下,为应用程序添加事务、日志等横切关注点。而通过ORM,我们可以方便地将Java对象映射到数据库中的表。 总结来说,Spring核心容器Spring框架最为重要的组成部分,它提供了BeanFactory和ApplicationContext两个接口,用于管理和组织应用程序中的组件。同时,它还包括了一些辅助模块,如AOP和ORM,以提供更多的功能支持。使用Spring核心容器,我们可以简化应用程序的开发、配置和管理,提高代码的可重用性和可维护性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值