Spring随笔

视频是黑马的SSM教程,传送门,记录些知识点,主要是概念使用,本篇不涉及源码相关。

1. Spring核心概念

Spring核心概念这部分内容中主要包含IOC/DIIOC容器Bean

1.1 提出概念前,项目中的问题?

(1)业务层需要调用数据层的方法,就需要在业务层new数据层的对象

(2)如果数据层的实现类发生变化,那么业务层的代码也需要跟着改变,发生变更后,都需要进行编译打包和重部署

(3)所以,现在代码在编写的过程中存在的问题是:耦合度偏高

针对这个问题,该如何解决呢?

我们就想,如果能把框中的内容给去掉,不就可以降低依赖了么,但是又会引入新的问题,去掉以后程序能运行么?

答案肯定是不行,因为bookDao没有赋值为Null,强行运行就会出空指针异常。

所以现在的问题就是,业务层不想new对象,运行的时候又需要这个对象,该咋办呢?

针对这个问题,Spring就提出了一个解决方案:

  • 使用对象时,在程序中不要主动使用new产生对象,转换为由外部提供对象

这种实现思就是Spring的一个核心概念

1.2 IOC、IOC容器、Bean、DI概念

1.2.1 IOC(Inversion of Control)控制反转

(1) 什么是控制反转呢?

使用对象时,由主动new产生对象转换为由外部提供对象,此过程中对象创建控制权由程序转移到外部,此思想称为控制反转。

  • 控制 :指的是对象创建(实例化、管理)的权力
  • 反转 :控制权交给外部环境(Spring 框架、IoC 容器)

(2) IOC容器的作用以及内部存放的是什么?

  • IOC容器类似于一个工厂,负责对象的创建、初始化等一系列工作
  • 被创建或被管理的对象在IOC容器中统称为Bean
  • IOC容器中放的就是一个个的Bean对象

在 Spring 中, IoC 容器是 Spring 用来实现 IoC 的载体, IoC 容器实际上就是个 Map(key,value),Map 中存放的是各种对象。

IOC源码阅读

1.2.2 DI(Dependency Injection)依赖注入

(1) 什么是依赖注入呢?

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

(2) IOC容器中的Bean需要根据具体的业务来建立关系

IOC和DI的目的就是充分解耦

  • 使用IOC容器管理bean(IOC)
  • 在IOC容器内将有依赖关系的bean进行关系绑定(DI)
  • 最终结果为:使用对象时不仅可以直接从IOC容器中获取,并且获取到的bean已经绑定了所有的依 赖关系.

1.2.3 小结

(1) 什么IOC/DI思想?

  • IOC:控制反转,控制反转的是对象的创建权
  • DI:依赖注入,绑定对象与对象之间的依赖关系

(2) 什么是IOC容器?

​ Spring创建了一个容器用来存放所创建的对象,这个容器就叫IOC容器

(3) 什么是Bean?

​ 容器中所存放的一个个对象就叫Bean或Bean对象

1.3 IOC相关

1.3.1 bean的基础配置

1
2
3
4
5
<bean
id="bean的唯一标识"
class="bean的全路径类名"
scope="bean的作用范围,有Singleton(默认)和prototype"
name="bean的别名"/>

1.3.2 bean的实例化

Spring的IOC实例化对象的三种方式:

  • 构造方法:底层用的是反射
  • 静态工厂
  • 实例工厂
    • FactoryBean

1.实例工厂的步骤:

​ (1) 配置:

1
2
<bean id="userFactory" class="com.itheima.factory.UserDaoFactory"/>
<bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>

​ (2) 创建实例化工厂对象,对应第一行配置;调用对象中的方法来创建bean,对应第二行的配置

​ 其中,factory-bean是工厂的实例对象;factory-method是工厂对象中的具体创建对象的方法名

2.FactoryBean的步骤:

实现FactoryBean接口,重写接口方法:

1
2
3
4
5
6
7
8
9
10
public class UserDaoFactoryBean implements FactoryBean<UserDao> {
// 代替原始实例工厂中创建对象的方法
public UserDao getObject() throws Exception {
return new UserDaoImpl();
}
// 返回所创建类的Class对象
public Class<?> getObjectType() {
return UserDao.class;
}
}

配置:

1
<bean id="userDao" class="com.itheima.factory.UserDaoFactoryBean"/>

FactoryBean接口有三个方法:

1
2
3
4
5
6
7
8
9
10
// 被重写后,会创建对象并返回
T getObject() throws Exception;

// 被重写后,返回被创建类的Class对象
Class<?> getObjectType();

default boolean isSingleton() {
return true;
}

1.3.3 bean的生命周期

  • Bean 容器找到配置文件中 Spring Bean 的定义。
  • Bean 容器利用 Java Reflection API 创建一个 Bean 的实例。
  • 如果涉及到一些属性值 利用 set()方法设置一些属性值。
  • 如果 Bean 实现了 BeanNameAware 接口,调用 setBeanName()方法,传入 Bean 的名字。
  • 如果 Bean 实现了 BeanClassLoaderAware 接口,调用 setBeanClassLoader()方法,传入 ClassLoader对象的实例。
  • 如果 Bean 实现了 BeanFactoryAware 接口,调用 setBeanFactory()方法,传入 BeanFactory对象的实例。
  • 与上面的类似,如果实现了其他 *.Aware接口,就调用相应的方法。
  • 如果有和加载这个 Bean 的 Spring 容器相关的 BeanPostProcessor 对象,执行postProcessBeforeInitialization() 方法
  • 如果 Bean 实现了InitializingBean接口,执行afterPropertiesSet()方法。
  • 如果 Bean 在配置文件中的定义包含 init-method 属性,执行指定的方法。
  • 如果有和加载这个 Bean 的 Spring 容器相关的 BeanPostProcessor 对象,执行postProcessAfterInitialization() 方法
  • 当要销毁 Bean 的时候,如果 Bean 实现了 DisposableBean 接口,执行 destroy() 方法。
  • 当要销毁 Bean 的时候,如果 Bean 在配置文件中的定义包含 destroy-method 属性,执行指定的方法。

bean的生命周期

1.3.4 核心容器总结

  • 容器相关

    • BeanFactory是IoC容器的顶层接口,初始化BeanFactory对象时,加载的bean延迟加载
    • ApplicationContext接口是Spring容器的核心接口,初始化时bean立即加载
    • ApplicationContext接口提供基础的bean操作相关方法,通过其他接口扩展其功能
    • ApplicationContext接口常用初始化类:ClassPathXmlApplicationContext(常用)、FileSystemXmlApplicationContext
  • bean相关

1.4 DI相关

两种注入方式:setter注入和构造器注入;两种数据类型:简单类型和引用类型。

1.4.1 setter注入

对于引用数据类型使用:

1
2
3
<bean ...>
<property name="" ref=""/>
</bean>

对于简单数据类型使用:

1
2
3
<bean ...>
<property name="" value=""/>
</bean>

1.4.2 构造器注入

对于引用类型:

1
2
3
4
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
<constructor-arg name="bookDao" ref="bookDao"/>
<constructor-arg name="userDao" ref="userDao"/>
</bean>

对于简单类型:

1
2
3
4
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
<constructor-arg name="databaseName" value="mysql"/>
<constructor-arg name="connectionNum" value="666"/>
</bean>

两个constructor-arg的顺序可以任意。

如果参数类型重复,可以通过配置index属性,来确认顺序:

1
2
3
4
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
<constructor-arg index="1" value="100"/>
<constructor-arg index="0" value="mysql"/>
</bean>

1.4.3 依赖注入小结