Spring学习笔记(一)
前言
Spring技术应该是Java框架技术的基础,也是从学习走向应用的第一步(很多使用java语言的公司会用SSM框架开发)。这份笔记正是结合自己的学习过程做了一份记录,如果对你有帮助,那我倍感荣幸,如果有什么错误,敬请大家指正。
自己学习框架时的感受:在本科期间是直接学SpringBoot框架的,当时学的非常懵,起初学习的感觉是注解太多了,压根记不下来,很多东西就单纯的知道怎么用,但是为什么也搞不清。作为理科生还是应该理清脉络,所以在此重新学习Spring框架。不多废话了,直接开始吧,与君共勉,一起加薪。
第一章:核心容器(Core Container)
1.1 Inversion of Control (IoC) container 控制反转容器
1.1.1 什么是控制反转容器
核心思想:将对象的创建控制权由程序转移到外部,这个思想叫做控制反转。
解释:对象就是我们new的那个东西,而它的创建控制权给了外部,就是我们现在不人工的写new了,而是交给Spring代理。
为什么我们要这么做?
答:传统代码代码耦合度过高,这个操作有助于解耦。
它是怎么做的?
答:Spring框架提供了一个容器,称为IoC容器,用来充当IoC思想的外部(核心思想)。IoC容器中管理的对象叫Bean。
1.1.2 Dependency Injection 依赖注入
什么是依赖注入?
举个例子:service层(服务层)的运行是需要dao层(数据层)做为依赖的。但是dao层里面的Bean呢(数据层里面肯定要用domian的对象啦)是在IoC容器中的,这个时候IoC容器直接将service和dao的依赖绑定,业务层要运行service时,Ioc容器直接给绑定的结果,叫依赖注入(DI)。
1.1.3 简单案例展示
-
第一步:使用IoC容器管理bean对象;(就是在配置文件中定义,或者是加一个@Bean注解)
-
第二步:用IoC容器内将有依赖关系的Bean进行关系绑定;(如何绑定呢?)
-
第三步:在配置文件中进行配置,如下图所示(图片来自黑马程序员的教学视频):
1.1.4 小结
没有学习框架之前,主要的操作其实就是增删改查,而有了框架之后,就是工作多做了几步,定义了Bean,做了信息的绑定,它的目的为了代码的解耦。
1.2 聊一聊Bean的相关操作
1.2.1 怎么实例化Bean
我们原来的操作是 Dog dog = new Dog(“哈士奇”); 现在我们不能new了,怎么代替?有三种方法可以代替。
- 方法一:使用构造方法实例化bean(Spring创建bean的时候调用的是无参的构造方法)
- 方法二:利用静态工厂实例化对象,注意要提供factory-method
- 方法三:实例工厂初始化bean,通过实现接口,规范化表述,实现接口。
其中用构造方法进行构造以及实例工程FactoryBean比较实用,展示如下:
构造方法
// Step1:提供可供访问的构造方法
public class BookDaoImpl implements BookDao {
public BookDaoImpl() {
System.out.println("book dao constructor is running ....");
}
public void save() {
System.out.println("book dao save ...");
}
}
// Step2:配置信息
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
// Step3:获得实例化对象
UserDao userDao2 = (UserDao) ctx.getBean("bookDao");
System.out.println(userDao1);
// 注意:
// 1. 这里无参构造方法如果不存在,将抛出异常BeanCreateException
// 2. 构造方法无论是 public 还是 private 都是可以正确运行的,内部是运用反射的原理
FactoryBean
// Step1:创建具有的FactoryBean类,实现FactoryBean方法
public class UserDaoFactoryBean implements FactoryBean<UserDao> {
// 代替原始实例工厂中创建对象的方法
public UserDao getObject() throws Exception {
return new UserDaoImpl();
}
public Class<?> getObjectType() {
return UserDao.class;
}
}
// Step2:配置信息
<bean id="userDao" class="com.itheima.factory.UserDaoFactoryBean"/>
// Step3:获得实例化对象
UserDao userDao = (UserDao) ctx.getBean("userDao");
System.out.println(userDao);
1.2.2 Bean的生命周期
配置bean的生命周期方法
// Step1:完成基本的实例化Bean的操作,并加上对应的init()和destory()方法
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
// 做初始化和销毁的方法,需要做配置 在配置文件中进行配置
//表示bean初始化对应的操作
public void init(){
System.out.println("init...");
}
//表示bean销毁前对应的操作
public void destory(){
System.out.println("destory...");
}
}
// Step2:在配置文件中进行配置(init-method、destroy-method)
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/>
// Step3:测试
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
ctx.close();
// 注意:
// 关闭容器可以测试destory方法,需要调用close方法。
Bean的整个生命周期的过程
一、初始化容器
-
创建对象(内存分配)
-
执行构造方法
-
执行属性注入(set操作)
-
执行bean初始化方法
二、使用bean
- 执行业务操作
三、关闭/销毁容器
- 执行bean销毁方法
1.2.3 依赖注入
定义
- 描述了在容器中建立bean与bean之间依赖关系的过程
依赖注入的方式(一共四种情况)
- setter注入
- 简单类型(基本数据类型和Spring)
- 引用类型
- 构造器注入
- 简单类型
- 引用类型
具体实现
- 第一种:使用setter方法的引用类型和简单类型
// 在bean中定义引用类型属性并提供可访问的set方法
public class BookDaoImpl implements BookDao {
private String databaseName;
private int connectionNum;
//setter注入需要提供要注入对象的set方法
public void setConnectionNum(int connectionNum) {
this.connectionNum = connectionNum;
}
//setter注入需要提供要注入对象的set方法
public void setDatabaseName(String databaseName) {
this.databaseName = databaseName;
}
public void save() {
System.out.println("book dao save ..." + databaseName + "," + connectionNum);
}
}
// 配置中使用property标签ref属性注入引用类型对象
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
// 简单类型 value进行配置
<property name="connectionNum" value="100"/>
<property name="databaseName" value="mysql"/>
</bean>
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
// 引用类型 ref进行配置
<!--property标签:设置注入属性-->
<!--name属性:设置注入的属性名,实际是set方法对应的名称-->
<!--ref属性:设置注入引用类型bean的id或name-->
<property name="bookDao" ref="bookDao"/>
<property name="userDao" ref="userDao"/>
</bean>
- 第二种:使用构造方法注入引用类型和简单类型
// 在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);
}
}
// 在配置文件中进行配置
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
// 这里是简单类型
<constructor-arg name="connectionNum" value="10"/>
<constructor-arg name="databaseName" value="mysql"/>
</bean>
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
// 这里是应用类型(name为方法的形参的名称)
<constructor-arg name="userDao" ref="userDao"/>
<constructor-arg name="bookDao" ref="bookDao"/>
</bean>
<constructor-arg index="0" type="int" ref="userDao"/>
1.2.4 依赖自动装配
定义
IoC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程成为自动装配
方式
- 按类型(常用)
- 按名称
- 按构造方法
- 不启用自动装配
& : Ioc的核心思想是不要自己new,我给你,但是需要一个入口。
实现方法
// 别的不变,在配置文件中加一个 autowire 并表明怎么自动装配
<bean class="com.itheima.dao.impl.BookDaoImpl"/>
<!--autowire属性:开启自动装配,通常使用按类型装配-->
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl" autowire="byType"/>