• SSM框架学习记录-Spring_day01


    1.核心概念


    当前项目中的问题

    下面代码的实现十分简单,但是业务层需要调用数据层的方法,就要在业务层new数据层的对象,如果数据层的实现类发生变化,业务层的代码也需要跟着改变,意味着要编译打包和重新部署


    // 数据层实现
    public class FoodDaoImpl implements FoodDao{
        public void save(){
            ...
        }
    }
    // 业务层实现
    public class FoodServiceImpl implements FoodService{
        private FoodDao fd = new FoodDaoImpl();
        public void save(){
            fd.save();
        }
    } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    IOC、IOC容器、Bean、DI*

    针对上述问题,Spring提出了一个解决方案:使用对象时,在程序中不要主动使用new产生对象,转换为由外部提供对象(Spring的核心概念)


    IOC(Inversion of Control)
    • 什么是控制反转IOC?使用对象时,由主动new产生对象转换为由外部提供对象,此过程中对象创建控制权由程序转移到外部
    • SpringIOC之间的关系是什么?
      • Spring技术对IOC思想进行了实现
      • Spring提供了一个容器(即IOC容器),用来充当IOC思想中的外部
    • IOC容器的作用以及内部存放的是什么?
      • IOC容器负责对象的创建、初始化等一系列工作,其中包含了数据层和业务层的类对象
      • 被创建或被管理的对象在IOC容器中统称为Bean
    • IOC容器中创建好servicedao对象后,程序能正确执行么?不行!service运行需要依赖dao对象,IOC容器中虽然有servicedao对象,但service对象和dao对象没有任何关系,需要将二者进行绑定
    DI(Dependency Injection)

    上述提到需要绑定对象间的关系,使用的就是DI


    • 什么是依赖注入DI?在容器中建立beanbean之间的依赖关系的整个过程称为依赖注入

    • IOC容器中哪些bean之间要建立依赖关系?如业务层需要依赖数据层,service就要和dao建立依赖关系

    目标

    充分解耦:

    • 使用IOC容器管理bean
    • IOC容器内将有依赖关系的bean进行关系绑定
    • 使用对象时不仅可以直接从IOC容器中获取,并且获取到的bean已经绑定了所有的依赖关系

    2.入门案例


    IOC入门

    思路分析

    1. Spring是使用容器来管理bean对象的,管什么?主要管理项目中所使用到的类对象,比如ServiceDao
    2. 如何将被管理的对象告知IOC容器?使用配置文件
    3. 被管理的对象交给IOC容器,要想从容器中获取对象先要获取IOC容器,如何获取?Spring框架提供相应的接口
    4. IOC容器得到后,如何从容器中获取bean?调用Spring框架提供对应接口中的方法
    代码实现

    参考Spring_01_quickstart


    DI入门

    分为思路和代码


    思路分析

    1. 要想实现依赖注入,必须要基于IOC管理bean
    2. Service中使用new形式创建的Dao对象是否保留?删除,因为要使用IOC容器中的bean对象
    3. Service中需要的Dao对象如何进入到Service中?在Service中提供方法(set方法),让IOC容器可以通过该方法传入bean对象
    4. ServiceDao间的关系如何描述?使用配置文件
    代码实现

    参考Spring_01_quickstart


    3.IOC相关内容


    bean基础配置

    主要掌握:

    • bean标签的idclass属性的使用
    • 对于是否设置单例的思考

    代码参考Spring_02_base_config


    • idbeanid,在容器中唯一

    • classbean的类型(即bean的全路径类名),注意不能使用接口(因为接口无法创建对象)

    • name:定义bean的别名,存在多个就使用,;或者空格分隔,之后在refgetBean方法中中也可以使用别名

    • scope:定义bean的作用范围,singleton表示单例(默认),prototype表示非单例

      • 为什么bean默认为单例?避免了对象的频繁创建与销毁,性能高

      • bean在容器中是单例的,会不会产生线程安全问题?

        • 如果对象是有状态对象(即该对象有成员变量可以用来存储数据的),所以会存在线程安全问题
        • 如果对象是无状态对象(即该对象没有成员变量没有进行数据存储),因方法中的局部变量在方法调用完成后会被销毁,所以不会存在线程安全问题
      • 哪些bean对象适合交给容器进行管理?

        • 表现层对象
        • 业务层对象
        • 数据层对象
        • 工具对象
      • 哪些bean对象不适合交给容器进行管理?

        • 封装实例的域对象,因为会引发线程安全问题
    bean实例化

    主要掌握:

    • bean是如何创建的?
    • 实例化bean的三种方式

    代码参考Spring_03_bean_instance


    • bean如何创建?使用反射,因为把构造方法设置为私有也可以使用bean,所以使用的是反射

    • 实例化bean的三种方式:

      • 构造方法实例化:调用的是无参构造方法,因为把无参构造方法删除,并且设置一个有参构造方法,运行时会报错
      <bean id="bookDao" class="com.psj.dao.impl.BookDaoImpl"/>
      
      • 1
      • 静态工厂实例化(了解即可):
      <bean id="orderDao" class="com.psj.factory.OrderDaoFactory" factory-method="getOrderDao"/>
      
      • 1
      • 实例工厂实例化(了解即可):和静态工厂的区别在于工厂中的方法一个是静态一个不是,并且配置也不同

        <bean id="userFactory" class="com.psj.factory.UserDaoFactory"/>
        <bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>
        
        • 1
        • 2
        • FactoryBean的使用:上述配置过于复杂,因为factory-method名称不固定每次都要配置,并且还需要特意创建id=userFactorybean配合使用
        // FactoryBean创建对象
        public class UserDaoFactoryBean implements FactoryBean<UserDao> {
            // 代替原始实例工厂中创建对象的方法(相当于统一了方法名为getObject)
            public UserDao getObject() throws Exception {
                return new UserDaoImpl();
            }
        
            public Class<?> getObjectType() {
                return UserDao.class;
            }
            
            // 如果要设置为单例/非单例,还可以实现isSingleton方法(不实现就取默认值-单例)
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        <bean id="userDao" class="com.psj.factory.UserDaoFactoryBean"/>
        
        • 1
    bean的生命周期

    bean生命周期指bean对象从创建到销毁的整体过程;bean生命周期控制指在bean创建后到销毁前做的事

    主要掌握:

    • 生命周期设置
    • bean的生命周期

    代码参考Spring_04_bean_lifecycle


    • 生命周期设置:

      • 添加初始化和销毁方法:分为不实现接口和实现接口两种
        • BooDaoImpl类中分别添加两个方法,方法名任意,
        • BookServiceImpl类中实现两个接口InitializingBeanDisposableBean,并实现接口中的方法afterPropertiesSetdestroy
      • 配置生命周期:对于不实现接口和实现接口两个情况,配置生命周期方式也不同
        • 不实现接口的方式需要在配置文件添加配置init-methoddestroy-method
        • 实现接口的方式则无需添加上述方法
    • 关闭容器(了解即可,因为交给Tomcat容器管理):不关闭容器无法执行消耗方法,关闭方式分为直接使用close方法和先注册钩子再使用close方法

    • bean的生命周期:

      • 初始化容器:
        1. 创建对象(内存分配)
        2. 执行构造方法
        3. 执行属性注入(set操作)
        4. 执行bean初始化方法
      • 使用bean:
        1. 执行业务操作
      • 关闭/销毁容器:
        1. 执行bean销毁方法

    4.DI相关内容


    依赖注入的两种方式

    主要掌握:

    • setter注入
    • 构造器注入
    • 两个方式的使用选择

    代码参考Spring_05_di_setSpring_06_di_constructor


    • setter注入:

      • 引用类型:详情见代码BookServiceImpl.javaapplicationContext.xml

      • 基本数据类型:和引用类型的区别在于applicationContext.xml中将ref改为value

      <bean id="bookDao" class="com.psj.dao.impl.BookDaoImpl">
          <property name="connectionNum" value="100"/>
          <property name="databaseName" value="mysql"/>
      bean>
      
      • 1
      • 2
      • 3
      • 4
    • 构造器注入:在实体类中添加有参构造器,主要修改在于applicationContext.xml

    • 引用类型:详情见代码中的applicationContext.xml,对于构造方法中形参名称和类型重复的问题也有说明

    • 基本数据类型:和引用类型的区别在于applicationContext.xml中将ref改为value

    • 使用选择:

      • 强制依赖(指对象在创建的过程中必须要注入指定的参数)使用构造器进行,使用setter注入有概率不进行注入导致null对象出现
      • 可选依赖(指对象在创建过程中注入的参数可有可无)使用setter注入进行,灵活性强
      • Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨
      • 如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用setter注入完成可选依赖的注入
      • 如果受控对象没有提供setter方法就必须使用构造器注入,自己开发的模块推荐使用setter注入
    自动装配

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

    主要掌握:

    • 自动装配的方式
    • 注意事项

    代码参考Spring_07_di_autoware


    • 自动装配方式:

      <bean id="bookService" class="com.psj.service.impl.BookServiceImpl" autowire="xxx"/>
      
      • 1
      • 按类型(常用):autowire="byType"
      • 按名称:autowire="byName",需要保证被依赖的beanid名和类中setter方法中把set删除并将首字母大写后的名称一致
      • 按构造方法
      • 不启用自动装配
    • 注意事项:

      • 自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效
      • 类中需要实现setter方法
      • 只能对引用类型依赖注入,不能对基本数据类型操作
    集合注入

    前面完成的是引用类型和基本数据类型的注入,还有集合类型(既可装基本数据类型也可装引用数据类型)未说明

    主要掌握:

    • 不同集合类型的注入

    代码参考Spring_08_di_collection


    • 不同集合类型的注入:详情见applicationContext.xml

      • property标签表示setter方式注入,构造方式注入constructor-arg标签内部也可以写标签
      • List的底层也是通过数组实现的,所以标签可混用
      • 集合中要添加引用类型,把标签改成标签即可
      <property name="array">
          <array>
              <ref bean="xxx">
          array>
      property>
      
      • 1
      • 2
      • 3
      • 4
      • 5

    参考


    https://www.bilibili.com/video/BV1Fi4y1S7ix?p=1-16

  • 相关阅读:
    认识时间复杂度和简单排序算法
    大数据之LibrA数据库系统告警处理(ALM-12035 恢复任务失败后数据状态未知)
    Java设计模式之代理模式
    leetcode.864 获取所有钥匙的最短路径 - bfs+状态压缩+最短路+位运算
    选择排序--java(详解)
    01-Redis核心数据结构与高性能原理
    按键精灵调用大漠插件源码例子
    基于springboot实现校友社交平台管理系统项目【项目源码+论文说明】
    图解MySQL逻辑备份的实现流程
    Java面试复习题汇总
  • 原文地址:https://blog.csdn.net/qq_41398418/article/details/128139438