Spring学习_Spring核心概念,IOC容器,DI依赖注入

目录

Spring介绍

学什么?     

怎么学

Spring体系结构

Spring核心概念

IOC (控制反转)

DI (依赖注入)

IOC入门案例

DI入门案例

Bean的配置

Bean起别名

Bean作用范围配置

Bean的实例化-三种方式

构造方式 [重点]

静态工厂方式

实例工厂方式

实现FactoryBean方式

Bean的生命周期 [了解]

Bean声明周期控制(定义方法)

Bean声明周期控制(实现接口)

Bean销毁时机

依赖注入(DI配置)

依赖注入俩种方式(重点)

setter方式注入

构造方式注入

参数适配

依赖注入方式选择

         依赖自动装配

         集合注入


Spring介绍

        为什么要学习Spring框架?

                Spring技术是JavaEE开发的必备技能,企业开发技术选型命中率>=90%

                废话不多说咱直接点进官网看看Spring | Home

         上面 这段话什么意思呢

Spring使Java编程对每个人来说都更快、更容易、更安全。Spring对速度、简单性和生产力的关注使其成为世界上最流行的Java框架

世界上最流行的Java框架,太有必要学习一下了👀

专业角度:

  1. 简化开发, 降低企业级开发的复杂性
  2. 框架整合, 高校整合其他技术, 提高企业级应用开发与运行效率

    学什么?     

  • 简化开发
    • IOC (控制反转)
    • AOP (面向切面编程)
  • 框架整合
    • MyBatis
    • MyBatis-plus

    怎么学

  • 学习Spring框架设计思想
  • 学习基础操作, 思考操作与思想间的联系
  • 学习案例, 熟练应用操作的同时, 体会思想

        Spring体系结构


Spring核心概念[重点]

        IOC (控制反转)

  • 使用对象时,由主动new产生对象转换为外部提供对象,此过程中对象创建控制权由程序转移到外部,此思想称为控制反转。通俗的讲就是“将new对象的权利交给Spring,我们从Spring中获取对象使用即可”, 大白话,咱不管创建, 咱直接拿来用.
  • Spring技术对IOC思想进行了实现
    • Spring提供了一个容器,称为IOC容器

        DI (依赖注入)

  • 在容器种建立 bean 与 bean 之间的依赖关系的过程,称为 依赖注入, 啥意思呢, 就是在一个Service的实现类中用到了Dao类中的方法,我们不用去new, Dao类的对象,直接调用方法即可

目标:

  • 使用IOC容器管理Bean
  • 在IOC容器中内将有依赖关系的bean进行关系绑定 (DI)

最终效果:

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


IOC入门案例[重点]

前边叭叭地说那么多,感觉听的也有点迷,咱呢,直接上波操作,不管是牛是马,拿出来遛一遛

案例的实现步骤

  1. 导入Spring坐标
  2. 定义Spring管理的类
  3. 创建Spring的配置文件, 配置对应类作为Spring管理的bean对象
  4. 初始化IOC容器(Spring核心容器/Spring容器), 通过容器获取bean对象

        没创建项目怎么导入坐标,拿什么导入? 

        前创建个项目, 创建一个Maven项目

        第一步, 导入Spring坐标

                pom.xml导入Spring坐标

    <dependencies>
        <!--    Spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.8.RELEASE</version>
        </dependency>
    </dependencies>

        第二步, 定义Spring管理的类 (接口)

         第三步, 创建Spring配置文件, 配置对应类作为Spring管理的bean对象

                定义applicationContext.xml配置文件并配置UserServiceImpl

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--
       bean标签:表示配置bean
       id属性:表示给bean起名字
       class属性:表示给bean定义类型
   -->
    <bean id="userService" class="priv.zlj.service.impl.UserServiceImpl"/>

</beans>

注意事项 :

        bean定义时,id属性在同一个上下文中(IOC容器中)不能重复.

         第四步, 初始化IOC容器(Sprng核心容器/Spring容器), 通过容器获取Bean对象

                再定义一个包名为test,用来测试

public class SpringTest {
    public static void main(String[] args) {
        ApplicationContext act = new ClassPathXmlApplicationContext("applicationContext.xml");

        UserService userService = (UserService) act.getBean("userService");

        userService.add();
    }
}

        运行结果



DI入门案例[重点]

案例的实现步骤

  1. 删除使用new的形式创建对象的代码 , 也就是 UserServiceImpl 类中的UserDao 对象
  2. 提供依赖对象对应的 setter 方法
  3. 配置service与dao之间的关系

         第一步,删除使用new的形式创建对象的代码

public class UserServiceImpl implements UserService {
    // 1.删除使用new的形式创建对象的代码
    private UserDao userDao;

    public void add() {
        System.out.println("UserServiceImpl");
        userDao.save();
    }
}

         第二步,提供对应的setter方法

public class UserServiceImpl implements UserService {
    // 1. 删除使用new的形式创建对象的代码
    private UserDao userDao;

    // 2. 提供对应的setter方法
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void add() {
        System.out.println("UserServiceImpl");
        userDao.save();
    }
}

         第三步,配置service与dao之间的关系

在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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="userDao" class="priv.zlj.dao.impl.UserDaoImpl"/>
    <!--
       bean标签:表示配置bean
       id属性:表示给bean起名字
       class属性:表示给bean定义类型
   -->

    <bean id="userService" class="priv.zlj.service.impl.UserServiceImpl">
        <!--3. 配置server与dao的关系
                property标签:表示配置当前bean的属性
                name属性:表示配置哪一个具体的属性
                ref属性:表示参照哪一个bean
		-->
        <property name="userDao" ref="userDao"/>
    </bean>

</beans>

 


详细地说明一下这俩个案例地实现

不说大白话有点太官方了,听不懂,咱讲点对我来说能听懂的........
在IOC案例中,
首先呢, 创建一个maven项目, 为什么用Maven呢, nb...
我们第一步, 在pom.xml中导入了Spring的依赖, 为什么要导入?... 没有人家的依赖,玩什么IOC,DI....
第二步, 定义Spring要管理的类, 也就是 dao,service
第三步, 类定义好了, 我们要对其进行配置, 不配置拿什么对象?? 创建了一个配置文件applicationContext.xml 并且配置了 UserServiceImpl 的一个bean., 在这里呢用到了一个标签 也就是 <bean>标签

<bean id="userService" class="priv.zlj.service.impl.UserServiceImpl" />

        ~ bean标签 : 表示配置bean

                ~ id属性 : 表示给bean 起个名字
                ~ class属性 : 表示给bean定义类型,也就是全类名,告诉人家,这个bean是哪来的

注意事项, 在一个IOC容器中,bean的定义时,id属性不能重复

第四步, 初始化这个容器,也就是加载这个配置文件[applicationContext.xml),通过容器获取对象

ApplicationContext act = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) act.getBean("userService");
userService.add();

在DI 这个案例中
我们首先删除了在UserServiceImpl类中的UserDao的实例化操作,也就是new, 之前我们一直在说的我们不用自己去new, 交给外部(Spring)创建, 现在,没有实例化UserDao的对象,我们要是运行的话,肯定会看到一个空指针异常,没实例化就调用方法,肯定会Null....空指针异常

所以我们第二步, 在UserServiceImpl类中提供对应的 setter 方法,为什么要提供setter方法呢,咱到后面在说, setter方法也有了, 这个时候就到 第三步了, 我们到applicationContext.xml文件中配置这俩的关系, 配UserServiceImpl和UserDao的关系, UserServiceImpl的bean我们有了, 还得创建个 UserDao的 bean吧, 不能说你没创建bean 我给你变出来一个吧, 

<bean id="userDao" class="priv.zlj.dao.impl.UserDaoImpl"/>
这时候,就要配置关系了, 在UserServiceImpl类中有一个属性 UserDao, 唉~,还有对应的setter方法, 能想到什么, 假如说我们没用Spring, 我们是不是可以调用对应的setter方法给UserDao实例化呢, 唉!, 不错,可以的, 只不过呢,我们现在不用去创建Service的对象再调用sett..方法了,在UserServiceImpl的bean标签中,有一个标签定义属性 也就是<property> 
 <bean id="userService" class="priv.zlj.service.impl.UserServiceImpl">
      <property name="userDao" ref="userDao"/>
  </bean>
        property标签:表示配置当前bean的属性
        name属性:表示配置哪一个具体的属性
        ref属性:表示参照哪一个bean
也就是说呢,咱创建对象的话,人家Spring都给包揽了, 咱就简单配置配置标签就能用, 很便捷,很soEasy~~.


Bean的配置

        Bean起别名

        还记得我们在上面哪个测试类中, 获取对象的方法吗, getBean("..");
        难道说在bean标签中只能通过 id 获取吗? × 

        在<bean> 标签中还提供了一个name 也就是定义bean的 别名, 可以定义多个, 使用逗号,分号, 空格 ,都可以(英文状态下)


        Bean作用范围配置

名称 : scope

类型 : 属性
所属 : bean标签
功能 : 定义bean的作用范围, 可选范围
                ~ singleton : 单例(默认)
                ~ prototype : 非单例
范例 : 

<bean id="userService" class="priv.zlj.service.impl.UserServiceImpl" scope="prototype" />

扩展:scope的取值不仅仅只有singleton和prototype,还有request、session、application、 websocket ,表示创建出的对象放置在web容器(tomcat)对应的位置。比如:request表示保存到request域中。

 实际开发中, 绝大部分的Bean 都是单例的, 也就是说绝大部分Bean不需要配置scope属性



Bean的实例化-三种方式

bean是如何创建的? 

        bean本质就是对象, 创建bean使用构造方法完成

        构造方式 [重点]

                还记得UserServiceImpl 这个类吗? 当我们在实例化这个类的时候, 一定会用到构造方法吧, 对吧, 那就有人说了, 唉~ 构造方法,我们没有创建阿, 哪里来的构造方法???蒙蔽,, !!!说没有构造方法的童鞋这个时候就可以去再复习Java基础了, 我们是不是有讲过, 当我们没有手动添加一个构造方法的时候, 编译器会自动赠送一个, 空参的构造方法, 那就懂了, 当我们使用bean标签创建对象的时候, 有一个class属性, 为什么要出传递全类名??? 可以想到什么?? 反射!!! 对,咱先不对其底层有过多的研究,到后面, 肯定还是要细细地学地,所以现在前不细细研究,
因为咱上面地IOC和DI案例就是用的构造方法实例化的, 在这, 我们就不粘贴了, 请大家动动你们发财的小手上去翻.

        静态工厂方式

        实例工厂方式

        实现FactoryBean<T>方式



Bean的生命周期 [了解]

  • 生命周期 : 从创建到消亡的完整过程
  • bean生命周期 : bean从创建到销毁的整体过程
  • bean生命周期控制 : 在bean创建后到销毁前做一些事情

        Bean声明周期控制(定义方法)

         在这里我们发现, init()方法执行了, 但是destory()方法没有执行??? Why? 为啥? 配置也配置了,你init()方法执行了, 我destory()方法难道就不配吗????

解决 :

                 为什么要替换一下ApplicationContext这个引用为ClassPathXmlApplicationContext呢, 因为ApplicationContext这个接口中没有close()这个方法,所以.....

                调用registerShutdownHook这个方法 

有一点不同,调用close方法必须在最后面调用否则就会抛出

 而调用registerShutdownHook方法在对象的后面哪里都可以调用

        Bean声明周期控制(实现接口)

        Bean销毁时机

容器关闭时触发bean的销毁

关闭容器的方式 :

        手动关闭容器 :

                ClassPathXmlApplicationContext 接口中的 close() 方法

        注册关闭钩子, 在虚拟机推出前先关闭容器再退出虚拟机

                ConfigurableApplicationContext接口registerShutdownHook()方法



依赖注入(DI配置)

        依赖注入俩种方式(重点)

                setter方式注入

                        简单类型

                        引用类型(常用)

                构造方式注入

                        简单类型

                        引用类型

        参数适配

  • 配置中使用 constructor-arg 标签 type 属性设置按形参类型注入
  • 配置中使用 constructor-arg 标签 index 属性设置按形参位置注入
     

        依赖注入方式选择

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

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

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

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

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

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

        依赖自动装配

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

自动装配方式 : 

  • 按类型(常用)
  • 按名称
  • 按构造方法
  • 不启用自动装配

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

 依赖自动装配特征 : 

  1. 自动装配用于引用类型依赖注入,不能对简单类型进行操作

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

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

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

        集合注入

<bean id="bookDao" class="priv.zlj.dao.impl.BookDaoImpl" >
        <property name="array">
            <array>
                <value>100</value>
                <value>200</value>
                <value>300</value>
            </array>
        </property>
        <property name="list">
            <list>
                <value>1</value>
                <value>2</value>
                <value>3</value>
                <value>4</value>
            </list>
        </property>
        <property name="set">
            <set>
                <value>1</value>
                <value>2</value>
                <value>3</value>
                <value>4</value>
            </set>
        </property>
        <property name="map">
            <map>
                <entry key="country" value="1"/>
                <entry key="province" value="2"/>
                <entry key="city" value="3"/>
            </map>
        </property>
        <property name="properties">
            <props>
                <prop key="country">china</prop>
                <prop key="province">henan</prop>
                <prop key="city">kaifeng</prop>
            </props>
        </property>
    </bean>

 说明:property标签表示setter方式注入,构造方式注入constructor-arg标签内部也可以写<array>、<list>、<set>、<map>、<props>标签



                                                                                                              time : 2022/12/11 18:00

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值