SSM框架学习——Spring的IoC与DI(容器、bean、依赖注入)

1. 核心概念

  • IoC(Inversion of Control)控制反转
    • 使用对象时,由主动new产生对象转换为由外部提供对象,此过程中对象创建控制权由程序转移到外部,此思想称为控制反转
  • Spring技术对IoC思想进行了实现
    • Spring提供了一个容器,称为IoC容器,用来充当IoC思想中的“外部
    • IoC容器负责对象的创建、初始化等一系列工作,被创建或被管理的对象在IoC容器中统称为Bean
  • DI(Dependency Injection)依赖注入
    • 在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入
  • 目标:充分解耦

2. IoC入门案例

1. 导入Spring坐标

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>spring_01_quickstart</artifactId>
    <version>1.0-SNAPSHOT</version>


    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

2. 定义Spring管理的类(接口)

public interface BookDao {
    public void save();
}
public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("book dao save ...");
    }
}
public interface BookService {
    public void save();
}
public class BookServiceImpl implements BookService {
    private BookDao bookDao = new BookDaoImpl();
    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }
}

3. 创建Spring配置文件,配置对应类作为Spring管理的bean

<?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="bookDao" class="com.lenyoo.dao.impl.BookDaoImpl"/>
    <bean id="bookService" class="com.lenyoo.service.impl.BookServiceImpl"/>
</beans>

注意:bean定义时id属性在同一个上下文中不能重复

4. 初始化IoC容器(Spring核心容器/Spring容器),通过容器获取bean

package com.lenyoo;

import com.lenyoo.dao.BookDao;
import com.lenyoo.service.BookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
        // 3. 获取IOC容器
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 4. 获取bean
//        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
//        bookDao.save();
        BookService bookService = (BookService) ctx.getBean("bookService");
        bookService.save();
    }
}

3. DI入门案例

1. 删除使用new的形式创建对象的代码

public class BookServiceImpl implements BookService {
    // 5. 删除业务层中使用new的方式创建的dao对象
    private BookDao bookDao /*= new BookDaoImpl()*/;
    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }

2. 提供依赖对象对应的setter方法

public class BookServiceImpl implements BookService {
    // 5. 删除业务层中使用new的方式创建的dao对象
    private BookDao bookDao;
    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }

    // 6. 提供对应的set方法
    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }
}

3. 配置service与dao之间的关系

<?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="bookDao" class="com.lenyoo.dao.impl.BookDaoImpl"/>

    <bean id="bookService" class="com.lenyoo.service.impl.BookServiceImpl">
        <!--7. 配置service与dao的关系-->
        <!--property标签表示配置当前bean的属性
        name表示配置哪一个具体的属性
        ref属性表示参照哪一个bean-->
    <property name="bookDao" ref="bookDao"/>
</bean>
</beans>

注意:配置中的两个bookDao的含义是不一样的
在这里插入图片描述

3. IoC相关内容

3.1 bean的基础配置

3.1.1 bean的name属性

在这里插入图片描述

3.1.2 bean的作用范围scope配置

在这里插入图片描述
在这里插入图片描述

3.2 bean实例化

对象已经能交给Spring的IOC容器来创建了,但是容器是如何来创建对象的呢?就需要研究下bean的实例化过程

3.2.1 实例化bean的三种方式——构造方法(常用)

  • 提供可访问的构造方法
public class BookDaoImpl implements BookDao {

    public BookDaoImpl() {
        System.out.println("book dao constructor is running ...");
    }

    public void save() {
        System.out.println("book dao save ...");
    }
}
  • 配置
	<!--方式一:构造方法实例化bean-->
    <bean id="bookDao" class="com.lenyoo.dao.impl.BookDaoImpl"/>
  • 无参构造方法如果不存在,将抛出异常BeanCreationException

3.2.2 实例化bean的三种方式——静态工厂(了解)

  • 静态工厂
public class OrderDaoFactory {
    public static OrderDao getOrderDao(){
        System.out.println("factory setup...");
        return new OrderDaoImpl();
    }
}
  • 配置
    <!--方式二:使用静态工厂实例化bean-->
    <bean id="orderDao" class="com.lenyoo.factory.OrderDaoFactory" factory-method="getOrderDao"/>

3.2.3 实例化bean的三种方式——实例工厂(了解)

  • 实例工厂
public class UserDaoFactory {
    public UserDao getUserDao(){
        return new UserDaoImpl();
    }
}
  • 配置
    <!--方式三:使用实例工厂实例化bean-->
    <bean id="userFactory" class="com.lenyoo.factory.UserDaoFactory"/>

    <bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>

在这里插入图片描述

3.2.4 实例化bean的第四种方式——FactoryBean(实用)

  • FactoryBean
public class UserDaoFactoryBean implements FactoryBean<UserDao> {
    // 代替原始实例工厂中创建对象的方法
    @Override
    public UserDao getObject() throws Exception {
        return new UserDaoImpl();
    }

    @Override
    public Class<?> getObjectType() {
        return UserDao.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}
  • 配置
    <!--方式四:使用FactoryBean实例化bean-->
    <bean id="userDao" class="com.lenyoo.factory.UserDaoFactoryBean"/>

3.3 bean的生命周期

(1)关于Spring中对bean生命周期控制提供了两种方式:

  • 在配置文件中的bean标签中添加init-methoddestroy-method属性
<bean id="bookDao" class="com.lenyoo.dao.impl.BookDaoImpl" 
	init-method="init" destroy-method="destroy"/>
  • 类实现InitializingBeanDisposableBean接口,这种方式了解下即可。
package com.lenyoo.service.impl;

import com.lenyoo.dao.BookDao;
import com.lenyoo.service.BookService;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

public class BookServiceImpl implements BookService, InitializingBean, DisposableBean {
    private BookDao bookDao;

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


    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }

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

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("service init");
    }
}

(2)对于bean的生命周期控制在bean的整个生命周期中所处的位置如下:

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

(3)关闭容器的两种方式:

  • ConfigurableApplicationContext是ApplicationContext的子类
    • close()方法
    • registerShutdownHook()方法
import com.lenyoo.dao.BookDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

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

        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        bookDao.save();
//        ctx.registerShutdownHook();
        ctx.close();
    }
}

4. DI相关内容

依赖注入方式,分别是:

  • setter注入
    • 简单类型
    • 引用类型
  • 构造器注入
    • 简单类型
    • 引用类型

4.1 Setter注入

4.1.1 Setter注入——引用类型

  • 在bean中定义引用类型属性,并提供可访问的set方法
public class BookServiceImpl implements BookService {
    private BookDao bookDao;
    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

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


    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
        userDao.save();
    }
    
}
  • 配置中使用property标签ref属性注入引用类型对象
    <bean id="bookDao" class="com.lenyoo.dao.impl.BookDaoImpl"/>
    <bean id="userDao" class="com.lenyoo.dao.impl.UserDaoImpl"/>

    <bean id="bookService" class="com.lenyoo.service.impl.BookServiceImpl">
        <property name="bookDao" ref="bookDao"/>
        <property name="userDao" ref="userDao"/>
    </bean>

4.1.2 Setter注入——简单类型

  • 在bean中定义简单类型属性并提供可访问的set方法
public class BookDaoImpl implements BookDao {

    private int connectionNum;
    private String databaseName;

    public void setConnectionNum(int connectionNum) {
        this.connectionNum = connectionNum;
    }

    public void setDatabaseName(String databaseName) {
        this.databaseName = databaseName;
    }

    public void save() {
        System.out.println("book dao save ..." + databaseName + "," + connectionNum);
    }

}
  • 配置中使用property标签value属性注入简单类型数据
    <bean id="bookDao" class="com.lenyoo.dao.impl.BookDaoImpl">
        <property name="databaseName" value="mysql"/>
        <property name="connectionNum" value="100"/>
    </bean>

4.2 构造器注入(了解)

4.2.1 构造器注入——引用类型(了解)

  • 在bean中定义引用类型属性并提供可访问的构造方法
public class BookServiceImpl implements BookService {
    private BookDao bookDao;
    private UserDao userDao;

    public BookServiceImpl(BookDao bookDao, UserDao userDao) {
        this.bookDao = bookDao;
        this.userDao = userDao;
    }
  • 配置中使用constructor-arg标签ref属性注入引用类型对象
<bean id="bookDao" class="com.lenyoo.dao.impl.BookDaoImpl"/>

<bean id="bookService" class="com.lenyoo.service.impl.BookServiceImpl">
	<constructor-arg name="bookDao" ref="bookDao"/>
    <constructor-arg name="userDao" ref="userDao"/>
</bean>

4.2.2 构造器注入——简单类型(了解)

  • 在bean中定义简单类型属性并提供可访问的构造方法
public class BookDaoImpl implements BookDao {

    private String databaseName;
    private int connectionNum;

    public BookDaoImpl(String databaseName, int connectionNum) {
        this.databaseName = databaseName;
        this.connectionNum = connectionNum;
    }

    public void save() {
        System.out.println("book dao save ..." + databaseName + "," + connectionNum);
    }

}
  • 配置中使用constructor-arg标签value属性注入简单类型数据
<bean id="bookDao" class="com.lenyoo.dao.impl.BookDaoImpl">
	<constructor-arg name="databaseName" value="mysql"/>
	<constructor-arg name="connectionNum" value="10"/>
</bean>

4.3 依赖自动装配

  • IoC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配
  • 自动装配方式
    • 按类型(常用)
    • 按名称
    • 按构造方法
    • 不启用自动装配
  • 配置中使用bean标签autowire属性设置自动装配的类型
<bean id="bookDao" class="com.lenyoo.dao.impl.BookDaoImpl"/>

<bean id="bookService" class="com.lenyoo.service.impl.BookServiceImpl" autowire="byType"/>

注意

  1. 自动装配用于引用类型依赖注入,不能对简单类型进行操作
  2. 使用按类型装配时(byType)必须保障容器中相同类型的bean唯一,推荐使用
  3. 使用按名称装配时(byName)必须保障容器中具有指定名称的bean,因变量名与配置耦合,不推荐使用
  4. 自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效

4.4 集合注入

public class BookDaoImpl implements BookDao {

    private int[] array;
    private List<String> list;
    private Set<String> set;
    private Map<String, String> map;
    private Properties properties;

    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;
    }

    public void save() {
        System.out.println("book dao save ...");
        System.out.println("遍历数组:" + Arrays.toString(array));
        System.out.println("遍历list:" + list);
        System.out.println("遍历Set:" + set);
        System.out.println("遍历Map:" + map);
        System.out.println("遍历Properties:" + properties);
    }

}

	<bean id="bookDao" class="com.lenyoo.dao.impl.BookDaoImpl">
        <property name="array">
            <array>
                <value>100</value>
                <value>200</value>
                <value>300</value>
            </array>
        </property>
        <property name="list">
            <list>
                <value>itcast</value>
                <value>itheima</value>
                <value>boxuegu</value>
            </list>
        </property>
        <property name="set">
            <set>
                <value>itcast</value>
                <value>itheima</value>
                <value>boxuegu</value>
                <value>chuanzhihui</value>
            </set>
        </property>
        <property name="map">
            <map>
                <entry key="country" value="china"/>
                <entry key="province" value="zhejiang"/>
                <entry key="city" value="hangzhou"/>
            </map>
        </property>
        <property name="properties">
            <props>
                <prop key="country">china</prop>
                <prop key="province">zhejiang</prop>
                <prop key="city">hangzhou</prop>
            </props>
        </property>
    </bean>

5. IOC/DI配置管理第三方bean

5.1 案例:数据源对象管理

该案例使用数据源Druid(德鲁伊)C3P0来配置学习
步骤1:导入第三方数据源依赖

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.16</version>
        </dependency>
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.16</version>
        </dependency>

步骤2:配置第三方bean

	<bean  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="root"/>
    </bean>

    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring_db"/>
        <property name="user" value="root"/>
        <property name="password" value="root"/>
        <property name="maxPoolSize" value="1000"/>
    </bean>

步骤3:从IOC容器中获取对应的bean对象

public class App {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        DataSource dataSource = (DataSource) ctx.getBean("dataSource");
        System.out.println(dataSource);
    }
}

5.2 加载properties文件

  • 开启context命名空间
<!--1. 开启context命名空间-->
<?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
       ">
</beans>
  • 使用context空间,加载指定properties文件
<!--2. 使用context空间加载properties文件-->
<context:property-placeholder location="jdbc.properties"/>
  • 使用属性占位符${}读取properties文件中的属性
<!--3. 使用属性占位符${}读取properties文件中的属性-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
	<property name="driverClassName" value="${jdbc.driver}"/>
	<property name="url" value="${jdbc.url}"/>
	<property name="username" value="${jdbc.username}"/>
	<property name="password" value="${jdbc.password}"/>
</bean>

<bean id="bookDao" class="com.lenyoo.dao.impl.BookDaoImpl">
	<property name="name" value="${jdbc.driver}"/>
</bean>

当有多个properties配置文件需要被加载,该如何配置?

  • 不加载系统属性
<context:property-placeholder location="jdbc.properties" system-properties-mode="NEVER"/>
  • 加载多个properties文件
<context:property-placeholder location="jdbc.properties,jdbc2.properties"/>
  • 加载所有properties文件
<context:property-placeholder location="*.properties"/>
  • 加载properties文件标准格式
<context:property-placeholder location="classpath:*.properties" system-properties-mode="NEVER"/>
  • 从类路径或jar包中搜索并加载properties文件
<context:property-placeholder location="classpath*:*.properties" system-properties-mode="NEVER"/>

6. 核心容器

6.1 容器的创建方式

  • 方式一:类路径加载配置文件
// 1. 加载类路径下的配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
  • 方式二:文件路径加载配置文件
// 2. 从文件系统下加载配置文件
ApplicationContext ctx = new FileSystemXmlApplicationContext("//Users/lenyoo/Documents/code/spring-app/spring_10_container/src/main/resources/applicationContext.xml");

6.2 bean的三种获取方式

  • 方式一:使用bean名称获取
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
  • 方式二:使用bean名称获取并指定类型
BookDao bookDao = ctx.getBean("bookDao", BookDao.class);
  • 方式三:使用bena类获取
BookDao bookDao = ctx.getBean(BookDao.class);

6.3 BeanFactory

  • 使用BeanFactory创建的容器是延迟加载
  • 使用ApplicationContext创建的容器是立即加载
  • 具体BeanFactory如何创建只需要了解即可。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值