Spring_IOC

1.1、Spring_IOC&DI概述

1.IOC和DI概述

IOC(Inversion of Control):其思想是反转资源获取的方向. 传统的资源查找方式要求组件向容器发起请求查找资源. 作为回应, 容器适时的返回资源. 而应用了 IOC 之后, 则是容器主动地将资源推送给它所管理的组件, 组件所要做的仅是选择一种合适的方式来接受资源. 这种行为也被称为查找的被动形式。

DI(Dependency Injection) — IOC 的另一种表述方式:即组件以一些预先定义好的方式(例如: setter 方法)接受来自如容器的资源注入. 相对于 IOC 而言,这种表述更直接

​	[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y28AjdLj-1640002393766)(image/wps1.jpg)]

2.IOC思想发展

IOC 前生 – 分离接口与实现:耦合度最高的方式,因为在报表服务类中需要知道接口及其每个实现类的细节

需求: 生成 HTML 或 PDF 格式的不同类型的报表.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lSzUmPxe-1640002393771)(image/wps4.jpg)]

IOC 前生 – 采用工厂设计模式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZCWwULOI-1640002393772)(image/wps5.jpg)]

IOC – 采用反转控制

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DsWuIdC0-1640002393785)(image/wps7.jpg)]

1.2、IOC 容器 BeanFactory & ApplicationContext 概述

1.BeanFactory

1.在 Spring IOC 容器读取 Bean 配置创建 Bean 实例之前, 必须对它进行实例化. 只有在容器实例化后, 才可以从 IOC 容器里获取 Bean 实例并使用.

2.Spring 提供了两种类型的 IOC 容器实现.

1).BeanFactory: IOC 容器的基本实现.

2).ApplicationContext: 提供了更多的高级特性. 是 BeanFactory 的子接口.

3).BeanFactory 是 Spring 框架的基础设施,面向 Spring 本身;ApplicationContext 面向使用 Spring 框架的开发者,几乎所有的应用场合都直接使用 ApplicationContext 而非底层的 BeanFactory

4).无论使用何种方式, 配置文件时相同的.

2.ApplicationContext

1.ApplicationContext 的主要实现类:

ClassPathXmlApplicationContext:从类路径下(bin目录下)加载配置文件

FileSystemXmlApplicationContext: 从文件系统中加载配置文件

2.ConfigurableApplicationContext 扩展于 ApplicationContext,新增加两个主要方法:refresh() 和 close(), 让 ApplicationContext 具有启动、刷新和关闭上下文的能力

3.ApplicationContext 在初始化上下文时就实例化所有单例的 Bean。

4.WebApplicationContext 是专门为 WEB 应用而准备的,它允许从相对于 WEB 根目录的路径中完成初始化工作

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZfT4m828-1640002393787)(image/1624204911277.png)]

1.3、依赖注入的方式

1.属性注入

1).属性注入即通过 setter 方法注入Bean 的属性值或依赖的对象

2).属性注入使用 元素, 使用 name 属性指定 Bean 的属性名称,value 属性或 子节点指定属性值

3).属性注入是实际应用中最常用的注入方式

<!-- name对应的是setXxx()中的xxx value是指将为类中的属性赋值-->
<bean id="helloWorld" class="com.etc.spring.ch01.HelloWorld">
    <property name="userName1" value="Spring"></property>
</bean>

2.构造方法注入

1).通过构造方法注入Bean 的属性值或依赖的对象,它保证了 Bean 实例在实例化后就可以使用。

2).构造器注入在 元素里声明属性, 中没有 name 属性

3).

索引匹配入参:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tV0kZ22p-1640002393798)(image/wps8.jpg)]

类型匹配入参:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yscWS54t-1640002393801)(image/1624205081803.png)]

1.4、属性配置细节

1.字面值

字面值:可用字符串表示的值,可以通过 元素标签或 value 属性进行注入。

基本数据类型及其封装类、String 等类型都可以采取字面值注入的方式。

若字面值中包含特殊字符,可以使用 ==<![CDATA[]]> ==把字面值包裹起来。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EBTFkGCR-1640002393802)(image/wps9.jpg)]

2.引用其它 Bean

1). 组成应用程序的 Bean 经常需要相互协作以完成应用程序的功能。 要使 Bean 能够相互访问, 就必须在 Bean 配置文件中指定对 Bean 的引用。

2). 在 Bean 的配置文件中, 可以通过 元素或 ref属性为 Bean 的属性或构造器参数指定对 Bean 的引用。

3).也可以在属性或构造器里包含 Bean 的声明, 这样的 Bean 称为内部 Bean.

  > 当 Bean 实例仅仅给一个特定的属性使用时, 可以将其声明为内部 Bean. 内部 Bean 声明直接包含在 <property> 或 <constructor-arg> 元素里, 不需要设置任何 id 或 name 属性
  > 内部 Bean 不能使用在任何其他地方

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xn9XBand-1640002393804)(image/1624205450396.png)]

3.级联属性

<?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="p" class="com.cm.ch02.ref.Person">
        <property name="username" value="李四"></property>
        <property name="age" value="35"></property>
        <property name="car" ref="c"></property>
        <!--
            通过级联属性操作修改车的价格
            1.等价于Person对象调用了setCar(),car对象调用了setPrice()
            2.属性需要先初始化赋值,否则会出现异常
        -->
        <property name="car.price" value="500000"></property>
    </bean>

    <bean id="c" class="com.cm.ch02.ref.Car">
        <property name="label" value="aodi"></property>
        <property name="price" value="300000"></property>
    </bean>

</beans>

4.集合属性

1.在 Spring中可以通过一组内置的 xml 标签(例如: , 或 ) 来配置集合属性.

2.配置 java.util.List 类型的属性, 需要指定 标签, 在标签里包含一些元素. 这些标签可以通过 指定简单的常量值, 通过 指定对其他 Bean 的引用. 通过 指定内置 Bean 定义. 通过 指定空元素.

3.数组的定义和 List 一样, 都使用

4.配置 java.util.Set 需要使用 标签, 定义元素的方法与 List 一样.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oaz2YnEU-1640002393807)(image/1624205680085.png)]

5.Java.util.Map 通过 标签定义, 标签里可以使用多个 作为子标签. 每个条目包含一个键和一个值.

6.必须在 标签里定义键

7.因为键和值的类型没有限制, 所以可以自由地为它们指定 , , 或 元素.

8.可以将 Map 的键和值作为 的属性定义: 简单常量使用 key 和 value 来定义; Bean 引用通过 key-ref 和 value-ref 属性定义

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YCGRAuZ9-1640002393809)(image/1624205700321.png)]

9.使用 utility scheme 定义集合

1).使用基本的集合标签定义集合时, 不能将集合作为独立的 Bean 定义, 导致其他 Bean 无法引用该集合, 所以无法在不同 Bean 之间共享集合.

2).可以使用 util schema 里的集合标签定义独立的集合 Bean. 需要注意的是, 必须在 根元素里添加 util schema 定义

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-76PLydKe-1640002393815)(image/1624206566669.png)]

5.p命名空间

1.为了简化 XML 文件的配置,越来越多的 XML 文件采用属性而非子元素配置信息。

2.Spring 从 2.5 版本开始引入了一个新的 p 命名空间,可以通过 元素属性的方式配置 Bean 的属性。

3.使用 p 命名空间后,基于 XML 的配置方式将进一步简化

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MKW2isJY-1640002393821)(image/1624206601107.png)]

1.5、Bean的作用域

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-toDnroXn-1640002393822)(image/1624206688663.png)]

1.在 Spring 中, 可以在 元素的 scope 属性里设置 Bean 的作用域.

2.默认情况下, Spring 只为每个在 IOC 容器里声明的 Bean 创建唯一一个实例, 整个 IOC 容器范围内都能共享该实例:所有后续的 getBean() 调用和 Bean 引用都将返回这个唯一的 Bean 实例.该作用域被称为 singleton, 它是所有 Bean 的默认作用域.

1.6、外部属性文件

1.在类路径下新建db.properties属性文件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0lyVAcHg-1640002393824)(image/image-20200713001742668.png)]

#mysql
db.name=root
db.password=12345678
db.jdbcUrl=jdbc:mysql://localhost:3306/dborder?useUnicode=true&characterEncoding=utf-8
db.driverClass=com.mysql.jdbc.Driver

2.修改pom.xml文件

<!--mysql驱动包 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.38</version>
</dependency>

<!--c3p0 -->
<dependency>
    <groupId>c3p0</groupId>
    <artifactId>c3p0</artifactId>
    <version>0.9.1.2</version>
</dependency>

注意:根据当前安装的mysql版本,选择合适的mysql驱动的版本号

3.新建spring的核心配置文件

<?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 https://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 导入外部属性文件 -->
    <context:property-placeholder location="classpath:db.properties" />

    <!-- 配置c3p0数据连接池 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <!-- 使用外部属性文件上的key -->
        <property name="user" value="${db.name}"></property>
        <property name="password" value="${db.password}"></property>
        <property name="jdbcUrl" value="${db.jdbcUrl}"></property>
        <property name="driverClass" value="${db.driverClass}"></property>
    </bean>

</beans>

4.测试

package com.cm.ch03.properties;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class MainTest {

    public static void main(String[] args) throws SQLException {

        ApplicationContext ac = new ClassPathXmlApplicationContext("beans_properties.xml");
        ComboPooledDataSource pool = (ComboPooledDataSource)ac.getBean("dataSource");
        System.out.println(pool);
        Connection connection = pool.getConnection();
        PreparedStatement preparedStatement = connection.prepareStatement("select * name from t_user where id=?");
        preparedStatement.setInt(1, 1);
        ResultSet resultSet = preparedStatement.executeQuery();
        while (resultSet.next()){
            System.out.println(resultSet.getString(1));
        }
        connection.close();
        pool.close();
    }

}

1.7、管理Bean的生命周期

1.Spring IOC 容器对 Bean 的生命周期进行管理的过程

1).通过构造器或工厂方法创建 Bean 实例

2).为 Bean 的属性设置值和对其他 Bean 的引用

3).调用 Bean 的初始化方法

4).Bean 可以使用了

5).当容器关闭close时, 调用 Bean 的销毁方法

在 Bean 的声明里设置 init-method 和 destroy-method 属性, 为 Bean 指定初始化和销毁方法.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nkNFaWGK-1640002393827)(image/1624207142631.png)]

2.创建 Bean 后置处理器

1.Bean 后置处理器允许在调用初始化方法前后对 Bean 进行额外的处理.

2.Bean 后置处理器对 IOC 容器里的所有 Bean 实例逐一处理, 而非单一实例. 其典型应用是: 检查 Bean 属性的正确性或根据特定的标准更改 Bean 的属性.

3.对Bean 后置处理器而言, 需要实现**BeanPostProcessor接口**. 在初始化方法被调用前后, Spring 将把每个 Bean 实例分别传递给上述接口的以下两个方法:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jFkYYehY-1640002393830)(image/1624207251843.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7uiM20WW-1640002393831)(image/1624207264116.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HJleoMkq-1640002393832)(image/1624207273596.png)]

3.添加 Bean 后置处理器后 Bean 的生命周期

1).通过构造器或工厂方法创建 Bean 实例

2).为 Bean 的属性设置值和对其他 Bean 的引用

3).将 Bean 实例传递给 Bean后置处理器的postProcessBeforeInitialization 方法

4).调用 Bean 的初始化方法

5).将 Bean 实例传递给 Bean 后置处理器的 postProcessAfterInitialization方法

6).Bean 可以使用了

7).当容器关闭时, 调用 Bean 的销毁方法

1.8、Bean 的配置方式

1.通过全类名的方式

2.通过工厂方法(静态工厂方法 & 实例工厂方法)

2.1 通过调用静态工厂方法创建 Bean

1.调用静态工厂方法创建 Bean是将对象创建的过程封装到静态方法中. 当客户端需要对象时, 只需要简单地调用静态方法, 而不需要关心创建对象的细节.

2.要声明通过静态方法创建的 Bean, 需要在 Bean 的 class 属性里指定拥有该工厂的方法的类, 同时在 factory-method 属性里指定工厂方法的名称. 最后, 使用 元素为该方法传递方法参数.

StaticCarFactory类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CCa8FUPB-1640002393834)(image/wps111.jpg)]

beans-factory.xml

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XetIbyrH-1640002393835)(image/wps222.jpg)]

2.2 通过调用实例工厂方法创建 Bean

1.实例工厂方法: 将对象的创建过程封装到另外一个对象实例的方法里. 当客户端需要请求对象时, 只需要简单的调用该实例方法而不需要关心对象的创建细节.

2.要声明通过实例工厂方法创建的 Bean

1).在 bean 的 factory-bean 属性里指定拥有该工厂方法的 Bean

2).在 factory-method 属性里指定该工厂方法的名称

3).使用 construtor-arg 元素为工厂方法传递方法参数

InstanceCarFactory类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pLmTGIxa-1640002393837)(image/image-20211213121146043.png)]

beans-factory.xml

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qKalF3Aw-1640002393838)(image/image-20211213121150391.png)]

3.通过FactoryBean的方式

1.Spring 中有两种类型的 Bean, 一种是普通Bean, 另一种是工厂Bean, 即FactoryBean.

2.工厂 Bean 跟普通Bean不同, 其返回的对象不是指定类的一个实例, 其返回的是该工厂 Bean 的 getObject 方法所返回的对象

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3n3NzZFK-1640002393839)(image/wps333.jpg)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YqSSa0n1-1640002393840)(image/wps444.jpg)]

1.9、Spring IOC 注解+XML版

基于注解配置Bean:标识使用注解将bean配置到IOC容器中

基于注解来装配Bean的属性:让bean与bean之间发生关联关系

1.组件扫描(component scanning)

Spring 能够从 classpath 下自动扫描, 侦测和实例化具有特定注解的组件.

2.特定组件包括

基于注解配置Bean

@Component: 基本注解, 标识了一个受 Spring 管理的组件

@Repository: 标识持久层dao层组件

@Service: 标识服务层(业务层)组件

@Controller: 标识表现层组件

基于注解来装配Bean的属性

@Value(""):给属性赋值,注入简单类型的属性 @Value(value=“abc”)private String name;

@Autowired:实现自动装配

3.对于扫描到的组件, Spring 有默认的命名策略

使用非限定类名, 第一个字母小写;也可以使用在注解中通过 value 属性值标识组件的名称。

value是默认的属性,所以可以将value省略不写;可以使用value属性值来标识bean在IOC容器中的id。

4.指定扫描包

当在组件类上使用了特定的注解之后, 还需要在 Spring 的配置文件中声明 <context:component-scan>表示要去扫描哪些包:

1).base-package 属性指定一个需要扫描的基类包,Spring 容器将会扫描这个基类包里及其子包中的所有类.

<?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 https://www.springframework.org/schema/context/spring-context.xsd">

	<!-- 指定Spring IOC容器扫描的包 -->
    <context:component-scan base-package="com.cm.ch04"></context:component-scan>

</beans> 

2).当需要扫描多个包时, 可以使用逗号分隔.

<!-- 指定Spring IOC容器扫描的包,当有多个包时,则可使用逗号隔开 -->
<context:component-scan base-package="com.cm.ch04 , com.cm.ch02"></context:component-scan>

3).如果仅希望扫描特定的类而非基包下的所有类,可使用 resource-pattern 属性过滤特定的类.

<!-- 指定Spring IOC容器扫描的包,通过resource-pattern指定扫描的资源 -->
<context:component-scan base-package="com.cm.ch04" resource-pattern="entity/*"></context:component-scan>

4).<context:include-filter> 子节点表示要包含的目标类

<context:exclude-filter> 子节点表示要排除在外的目标类

<context:component-scan>下可以拥有若干个<context:include-filter> 和 <context:exclude-filter> 子节点。

<context:include-filter>和<context:exclude-filter>子节点支持多种类型的过滤表达式:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F9C2CDdt-1640002393847)(image/1624207666578.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kHe1jIPG-1640002393852)(image/1624207675347.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5du1ZtPq-1640002393855)(image/1624207684616.png)]

5.基于注解方式实现属性注入

(1)@Autowired:根据属性类型进行自动装配

第一步 把 service 和 dao 对象创建,在 service 和 dao 类分别添加创建对象注解@Service和@Repository

第二步 在 service 注入 dao 对象,在 service 类添加 dao 类型属性,在属性上面使用注解

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DuKx3HNZ-1640002393856)(image/1624207782369.png)]

(2)@Qualifier:根据名称进行注入

这个@Qualifier 注解的使用,和上面@Autowired 一起使用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-97o3Pd9i-1640002393858)(image/1624207914606.png)]

(3)@Resource:可以根据类型注入,可以根据名称注入

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ymrAgIEO-1640002393868)(image/1624207952567.png)]

1.10、Spring IOC 配置类+注解版

1.新建Java Config的配置类

//@Configuration 标注当前类,是一个Java Config的配置类
@Configuration
//@ComponentScan 指定扫描包
@ComponentScan(basePackages = {"com.igeek.ch09.config"})
public class MyConfig {

    //@Bean 

}

2.基于注解配置Bean

//@Component注解,基础注解,一旦标注此类,代表这个类,将交由spring的IOC容器管理
//注解,若不指定value值,则有默认的命名策略,类名首字母小写作为它的beanName
@Component
public class User {
}

//@Repository 标注当前类是数据交互层的类
//注解,若不指定value值,则有默认的命名策略,类名首字母小写作为它的beanName
@Repository
public class UserDao {
}

//@Service 标注是一个业务逻辑层的类
//注解,若不指定value值,则有默认的命名策略,类名首字母小写作为它的beanName
@Service(value = "userServiceImpl")
public class UserService{
}

//@Controller 标注当前这个类是一个控制层的类
//注解,若不指定value值,则有默认的命名策略,类名首字母小写作为它的beanName
@Controller
public class UserController {
}

3.基于注解来装配Bean的属性

@Component
public class User {
    //@Value注解,相当于在xml中给属性注入值时的value属性;给简单类型的数据赋值
    @Value(value = "李四")
    private String username;
    @Value("22")
    private int age;
}


@Controller
public class UserController {
    //@Autowired  根据属性类型进行自动装配,直接在IOC容器中找到与之类型匹配的bean实例
    @Autowired(required = false)
    private UserService service;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

what's your name.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值