Spring

发布时间 2023-07-18 00:11:05作者: 溯鸣

Spring技术是JavaEE开发必备技能,企业开发技术选型命中率>90%。
专业角度:
  简化开发,降低企业级开发的复杂性。
  框架整合,高效整合其他技术,提高企业级应用开发与运行效率。

Spring Framework系统架构
  Spring Framework是Spring生态圈中最基础的项目,是其他项目的根基。

Spring核心概念

代码书写现状:耦合度偏高
解决方案:使用对象时,在程序中不要主动使用new产生对象,转换为由外部提供对象
IoC(Inversion of Control)控制反转:对象的创建控制权由程序转移到外部,这种思想称为控制反转

IoC(Inversion of Control)控制反转

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

Spring技术对IoC思想进行了实现
  Spring提供了一个容器,称为IoC容器,用来充当IoC思想中的“外部”
  IoC容器负责对象的创建、初始化等一系列工作,被创建或被管理的对象在IoC容器中统称为Bean

DI(Dependency Injection)依赖注入

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

目标:充分解耦
  使用IoC容器管理bean(IoC)
  在IoC容器内将有依赖关系的bean进行关系绑定(DI)
最终效果:使用对象时不仅可以直接从IoC容器中获取,并且获取到的bean已经绑定了所有的依赖关系

IOC和DI入门案例(重点)

Ioc入门案例

1、在pom.xml中导入Spring坐标

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.2.10.RELEASE</version>
    </dependency>
</dependencies>

2、定义Spring管理的类(接口)
  BookDao接口和BookDaoImpl实现类

1 public interface BookDao {
2     public void save();
3 }
4 
5 public class BookDaoImpl implements BookDao {
6     public void save() {
7         System.out.println("book dao save ...");
8     }
9 }

  BookService接口和BookServiceImpl实现类

 1 public interface BookService {
 2     public void save();
 3 }
 4 
 5 public class BookServiceImpl implements BookService {
 6     private BookDao bookDao = new BookDaoImpl();
 7     public void save() {
 8         System.out.println("book service save ...");
 9         bookDao.save();
10     }
11 }

3、创建Spring配置文件,配置对应类作为Spring管理的bean对象
  在resources下定义applicationContext.xml配置文件并配置BookServiceImpl

<?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="bookService" class="com.test.service.impl.BookServiceImpl"></bean>

</beans>

  注:bean定义时id属性在同一个上下文中(IOC容器中)不能重复
4、初始化IOC容器(Spring核心容器/Spring容器),通过容器获取Bean对象

 1 public class App {
 2     public static void main(String[] args) {
 3         //1.创建IoC容器对象,加载spring核心配置文件
 4         ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
 5         //2 从IOC容器中获取Bean对象(BookService对象)
 6         BookService bookService= (BookService)ctx.getBean("bookService");
 7         //3 调用Bean对象(BookService对象)的方法
 8         bookService.save();  //book service save ...  book dao save ...
 9     }
10 }

DI入门案例

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

1 public class BookServiceImpl implements BookService {
2     private BookDao bookDao;  //【第一步】删除使用new的形式创建对象的代码
3     public void save() {
4         System.out.println("book service save ...");
5         bookDao.save();
6     }
7 }

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

 1 public class BookServiceImpl implements BookService {
 2     private BookDao bookDao;
 3     public void save() {
 4         System.out.println("book service save ...");
 5         bookDao.save();
 6     }
 7     //【第二步】提供依赖对象对应的setter方法
 8     public void setBookDao(BookDao bookDao) {
 9         this.bookDao = bookDao;
10     }
11 }

3、配置service与dao之间的关系
  在applicationContext.xml中配置

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
 5     <!--
 6         bean标签:表示配置bean
 7         id属性:表示给bean起名字
 8         class属性:表示给bean定义类型
 9     -->
10     <bean id="bookDao" class="com.test.dao.impl.BookDaoImpl"/>
11 
12     <bean id="bookService" class="com.test.service.impl.BookServiceImpl">
13         <!--配置server与dao的关系
14             property标签:表示配置当前bean的属性
15             name属性:表示配置哪一个具体的属性
16             ref属性:表示参照哪一个bean
17         -->
18         <property name="bookDao" ref="bookDao"/>
19     </bean>
20 </beans>

  图解演示

  

bean

bean配置

bean基础配置(重点)

Bean别名配置

注:获取bean无论是通过id还是name获取,如果无法获取到,将抛出异常NoSuchBeanDefinitionException
  NoSuchBeanDefinitionException: No bean named 'bookServiceImpl' available

Bean作用范围配置(重点)

扩展:scope的取值不仅仅只有singleton和prototype,还有request、session、application、 websocket ,表示创建出的对象放置在web容器(tomcat)对应的位置。比如:request表示保存到request域中。
注:在我们的实际开发当中,绝大部分的Bean是单例的,也就是说绝大部分Bean不需要配置scope属性。

bean实例化

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

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

BookDaoImpl实现类-提供可访问的构造方法(默认,可不写)

1 public class BookDaoImpl implements BookDao {
2     public BookDaoImpl() {
3         System.out.println("book dao constructor is running ....");
4     }
5     public void save() {
6         System.out.println("book dao save ...");
7     }
8 }

applicationContext.xml配置

<bean id="bookDao" class="com.test.dao.impl.BookDaoImpl"/>

无参构造方法如果不存在,将抛出异常BeanCreationException

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

OrderDao接口和OrderDaoImpl实现类

1 public interface OrderDao {
2     public void save();
3 }
4 public class OrderDaoImpl implements OrderDao {
5     public void save() {
6         System.out.println("order dao save ...");
7     }
8 }

OrderDaoFatory工厂类

1 //静态工厂创建对象
2 public class OrderDaoFactory {
3     public static OrderDao getOrderDao(){
4         System.out.println("factory setup....");
5         return new OrderDaoImpl();
6     }
7 }

applicationContext.xml配置

<bean id="orderDao" class="com.test.factory.OrderDaoFactory" factory-method="getOrderDao"/>

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

UserDao接口和UserDaoImpl实现类

1 public interface UserDao {
2     public void save();
3 }
4 public class UserDaoImpl implements UserDao {
5     public void save() {
6         System.out.println("user dao save ...");
7     }
8 }

UserDaoFactory工厂类

1 //实例工厂创建对象
2 public class UserDaoFactory {
3     public UserDao getUserDao(){
4         return new UserDaoImpl();
5     }
6 }

applicationContext.xml配置

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

实例化bean的第四种方式————实现FactoryBean<T>方式扩展,了解)

定义UserDaoFactoryBean实现FactoryBean<UserDao>
  UserDaoFactoryBean中实例化什么类型的对象泛型就是该类型。

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

applicationContext.xml配置

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

Bean的生命周期【了解】

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

Bean生命周期控制

1、提供生命周期控制方法

 1 public class BookDaoImpl implements BookDao {
 2     public void save() {
 3         System.out.println("book dao save ...");
 4     }
 5     //表示bean初始化对应的操作
 6     public void init(){
 7         System.out.println("init...");
 8     }
 9     //表示bean销毁前对应的操作
10     public void destory(){
11         System.out.println("destory...");
12     }
13 }

applicationContext.xml配置

<!--init-method:设置bean初始化生命周期回调函数,此处填写init方法名-->
<!--destroy-method:设置bean销毁生命周期回调函数,仅适用于单例对象,此处填写destory方法名-->
<bean id="bookDao" class="com.test.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/>

测试类

 1 public class AppForLifeCycle {
 2     public static void main( String[] args ) {
 3         //此处需要使用实现类类型,接口类型没有close方法
 4         ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
 5         BookDao bookDao = (BookDao) ctx.getBean("bookDao");
 6         bookDao.save();
 7         //关闭容器,执行销毁的方法
 8         ctx.close();
 9     }
10 }

2、实现InitializingBean, DisposableBean接口

 1 public class BookServiceImpl implements BookService, InitializingBean, DisposableBean {
 2     private BookDao bookDao;
 3     public void setBookDao(BookDao bookDao) {
 4         System.out.println("set .....");
 5         this.bookDao = bookDao;
 6     }
 7     public void save() {
 8         System.out.println("book service save ...");
 9         bookDao.save();
10     }
11     public void destroy() throws Exception {
12         System.out.println("service destroy");
13     }
14     public void afterPropertiesSet() throws Exception {
15         System.out.println("service init");
16     }
17 }

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

Bean销毁时机

容器关闭前触发bean的销毁。
关闭容器方式:
  手工关闭容器;
    ConfigurableApplicationContext接口close()操作
  注册关闭钩子,在虚拟机退出前先关闭容器再退出虚拟机。
    ConfigurableApplicationContext接口registerShutdownHook()操作

 1 public class AppForLifeCycle {
 2     public static void main( String[] args ) {
 3         //此处需要使用实现类类型,接口类型没有close方法
 4         ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
 5 
 6         BookDao bookDao = (BookDao) ctx.getBean("bookDao");
 7         bookDao.save();
 8         //注册关闭钩子函数,在虚拟机退出之前回调此函数,关闭容器
 9         ctx.registerShutdownHook();
10         //关闭容器
11         //ctx.close();
12     }
13 }

依赖注入(DI配置)

依赖注入方式(重点

依赖注入的两种方式:
1、setter注入
  简单类型
  引用类型(很常用)
2、构造器注入
  简单类型
  引用类型

1.1 setter注入——引用类型

在bean中定义引用类型属性并提供可访问的set方法

1 public class BookServiceImpl implements BookService{
2     private BookDao bookDao;
3     public void setBookDao(BookDao bookDao) {
4         this.bookDao = bookDao;
5     }
6 }

配置中使用property标签ref属性注入引用类型对象

<bean id="bookService" class="com.test.service.impl.BookServiceImpl">   
    <property name="bookDao" ref="bookDao"/>
</bean>
<bean id="bookDao" class="com.test.dao.impl.BookDaoImpl"/>

1.2 setter注入——简单类型

在bean中定义简单类型属性并提供可访问的set方法

1 public class BookDaoImpl implements BookDao {
2     private int connectionNumber;
3     public void setConnectionNumber(int connectionNumber) {
4         this.connectionNumber = connectionNumber;
5     }
6 }

配置中使用property标签value属性注入简单类型数据

1 <bean id="bookDao" class="com.test.dao.impl.BookDaoImpl">
2     <property name="connectionNumber" value="10"/>
3 </bean>

2.1 构造器注入——引用类型

在bean中定义引用类型属性并提供可访问的构造方法

1 public class BookServiceImpl implements BookService{
2     private BookDao bookDao;
3     public BookServiceImpl(BookDao bookDao) {
4         this.bookDao = bookDao;
5     }
6 }

配置中使用constructor-arg标签ref属性注入引用类型对象

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

2.2 构造器注入——简单类型

在bean中定义简单类型属性并提供可访问的构造方法

1 public class BookDaoImpl implements BookDao {
2     private int connectionNumber;   
3     public void BookDaoImpl(int connectionNumber) {      
4         this.connectionNumber = connectionNumber;   
5     }
6 }

配置中使用constructor-arg标签value属性注入简单类型数据

<bean id="bookDao" class="com.test.dao.impl.BookDaoImpl">
    <constructor-arg name="connectionNumber" value="10"/>
</bean>

2.3 构造器注入——参数适配(了解)

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

<bean id="bookDao" class="com.test.dao.impl.BookDaoImpl">
    <constructor-arg type="int" value="10"/>
    <constructor-arg type="java.lang.String" value="mysql"/>
</bean>

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

<bean id="bookDao" class="com.test.dao.impl.BookDaoImpl">
    <constructor-arg index="0" value="10"/>
    <constructor-arg index="1" value="mysql"/>
</bean>

依赖注入方式选择

1.强制依赖使用构造器进行,使用setter注入有概率不进行注入导致null对象出现
2.可选依赖使用setter注入进行,灵活性强
3.Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨
4.如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用setter注入完成可选依赖的注入
5.实际开发过程中还要根据实际情况分析,如果受控对象没有提供setter方法就必须使用构造器注入
6.自己开发的模块推荐使用setter注入

依赖自动装配(理解)

IoC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配
自动装配方式:
  按类型(常用)
  按名称
  按构造方法
  不启用自动装配

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

<bean id="bookDao" class="com.test.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.test.service.impl.BookServiceImpl" autowire="byType"/>

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