Spring配置相关

Spring

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

初识Spring

了解Spring家族

  • Spring官网:https://spring.io/
  • Spring发展到今天已经形成了一种开发的生态圈,Spring提供了若干个项目,每个项目用于完成特定的功能
  • 重点学习
    • Spring Framework
    • Spring Boot
    • Spring Cloud

Spring Framework

Spring Framework系统架构

  • SpringFramework是Spring生态圈中最基础的项目,是其他项目的根基

Spring Framework系统架构图:

image.png

核心概念

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

IoC入门

1、利用Maven导入Spring的坐标 spring-context

<dependency>  
    <groupId>org.springframework</groupId>  
    <artifactId>spring-context</artifactId>  
    <version>6.1.6</version>  
</dependency>

2、创建配置文件:在 resources 目录下创建 applicationContext.xml 文件。

3、配置bean

# bean标签标识配置bean
# id属性表示bean的名字
# class属性表示bean的定义类型

<bean id="" class=""></bean>

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

4、获取Ioc容器

public static void main(String args[]){
	//获取IoC容器
	//ApplicationContext是一个接口,我们new一个它的实现对象
	//参数是我们的配置文件
	ApplicationContext ctx = new ClassPathXmlApplicationContext
	("applicationContext.xml");
	//获取bean
	//xml文件下配置bean的id名
	BookService bs =  ctx.getBean("bookService");
	//这时候就获取到Ioc容器中bean的对象了
}

DI入门

  1. 基于Ioc管理bean
  2. 通过配置进行依赖注入
<bean id="Dao" class="com.fyislo.dao.impl.Dao"/>

<bean id="Service" class="com.fyislo.service.impl.Service">
	# property标签表示配置当前bean的属性
	# name属性表示我们配给谁?(属性名称)
	# ref属性表示我们要把谁给对方(bean的id属性)
	<property name="dao" ref="Dao"/>
</bean>

Bean

Bean的配置

使用 name 属性,可以给bean配置多个别名。多个别名之间可以用逗号,分号,空格分隔。

<bean id="Dao" class="com.fyislo.dao.impl.Dao"/>

# name属性可以给bean配置多个别名。多个别名之间可以用逗号,分号,空格分隔。
<bean id="Service" name="service service2" class="com.fyislo.service.impl.Service">
	<property name="dao" ref="Dao"/>
</bean>

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

bean的作用范围

Spring给我们创建的bean默认是单例的。

如果需要非单例的bean,则需要在配置文件 <bean> 的标签中添加一个属性: scope

  • scoper
    • singleton:单例(默认)
    • prototype:非单例
<bean id="Service" name="service service2" class="com.fyislo.service.impl.Service" scope="prototype">
	<property name="dao" ref="Dao"/>
</bean>
  • 适合交给容器进行管理的bean
    • 表现层对象
    • 业务层对象
    • 数据层对象
    • 工具对象
  • 不适合交给容器进行管理的bean
    • 封装实体类的域对象

bean的实例化

1、使用构造方法完成创建bean(无参构造)

  • bean本质上就是对象
  • 无参构造如果不存在,将抛出异常 BeanCreationException

2、通过静态工厂创建bean(了解)

通过 class 属性告诉工厂类,在通过factory-method属性告诉Spring工厂里面的哪个方法是造对象的。

<bean id="orderDao" class="factory.OrderDaoFactory" factory-method="getorderDad"/>

3、实例工厂创建bean

  1. 先配置工厂的bean
  2. 通过 factory-bean 指定实例工厂的bean
  3. 通过 factory-method 指定造对象的方法
<bean id="userFactory" class="factory.UserDaoFactory"/>

<bean id="orderDao" factory-method="getuserDao" factory-bean="userFactory"/>

4、使用 FactoryBean<T> 实例化

实现接口中的两个方法。

public class UserDaoFactoryBean implements FactoryBean<UserDao>{
	//代替原始实例工厂中创建对象的方法
	//得到bean的实例
	public UserDao getobject() throws Exception{
		return new UserDaoImpl();
	}
	//得到bean的类型
	public Class<?> getobjectType(){
		//返回创建对象的字节码文件
		return UserDao.class;
	}
	//设置该bean是单例还是非单例的
	//默认可以不写该方法
	public boolean isSingleton(){
		//返回true:单例
		//返回false:非单例
		return true;
	}
}

这时候配置就很简便了

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

bean的生命周期

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

<bean>标签中init-method 属性可以指定一个方法,在bean创建前运行一个方法。

<bean> 标签中 destroy-method 属性可以指定一个方法,在bean销毁前运行的一个方法。

<bean id="" class="" init-method="init" destroy-method="destory"/>

关闭容器

public static void main(String args[]){
	//获取IoC容器
	//ApplicationContext是一个接口,但是它没有close()方法。
	//ClassPathXmlApplicationContext是它的实现类,有close()方法。
	ClassPathXmlApplicationContext ctx = new 
	ClassPathXmlApplicationContext
	("applicationContext.xml");

	//方法一:直接关闭容器
	ctx.close();
	//方法二:注册关闭钩子,在任何时间注册都可以。
	//作用:在虚拟机退出之前,把容器关完了再退出
	ctx.registerShutdownHook();
}

使用Spring接口来控制生命周期(这样便不用去xml文件中指定控制生命周期的方法)

实现 InitializingBeanDisposableBean 两个接口

public class Service implements InitializingBean, DisposableBean{
	public void afterPropertiesSet() throws Exception{
		//设置属性之后执行该方法
	}
	
	public void destroy() throws Exception{
		//
	}
}

Bean在初始化过程中经历的阶段

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

bean销毁时机

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

bean相关属性

image.png

依赖注入

  • 依赖注入的两种方式
    • 普通方法(set方法)
    • 构造方法
  • 依赖注入的两种类型
    • 引用类型
    • 简单类型(基本数据类型和String)
  • 依赖注入方式
    • setter注入
      • 简单类型
      • 引用类型
    • 构造器注入
      • 简单类型
      • 引用类型

setter方式注入

1、setter方式注入引用类型,在DI入门已有提过。

在xml文件中配置 <bean> 标签,并在其中配置 <property> 标签即可

2、setter方式注入简单类型

<bean id="Service" class="com.fyislo.service.impl.Service">
	# property标签表示配置当前bean的属性
	# name属性表示我们配给谁?(属性名称)
	# 只需要把ref属性替换成value属性,即可完成简单类型的注入
	<property name="int" value="123"/>
	<property name="string" value="name"/>
</bean>

构造器注入

1、构造器注入引用类型

将setter注入的set方法更换为有参构造即可,在xml的配置有所改变,如下:

<bean id="Service" class="com.fyislo.service.impl.Service">
	# 只需把property标签更换为constructor-arg标签即可
	<constructor-arg name="形参的名称1" ref=""/>
	<constructor-arg name="形参的名称2" ref=""/>
</bean>

2、构造器注入简单类型

# 标准写法:有指定形参的名称
<bean id="Service" class="com.fyislo.service.impl.Service">
	# 只需把constructor-arg标签的ref更换为value即可
	<constructor-arg name="形参的名称1" value=""/>
	<constructor-arg name="形参的名称2" value=""/>
</bean>
# 解决形参名称耦合的问题
<bean id="Service" class="com.fyislo.service.impl.Service">
	# 不使用name指定形参名称,使用type指定形参类型
	<constructor-arg type="int" value=""/>
	<constructor-arg type="java.lang.String" value=""/>
</bean>
# 解决参数类型重复问题,使用位置解决参数匹配
<bean id="Service" class="com.fyislo.service.impl.Service">
	# 使用index指定参数位置
	<constructor-arg index="0" value=""/>
	<constructor-arg index="1" value=""/>
</bean>

依赖注入方式选择

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

依赖自动装配

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

前提:想要自动装配,要提供set方法,xml配置文件如下:

  • autowire可选值
    • byType:按类型
    • byName:按名称
# 自动装配,使用aotuwire属性
# 该类型的bean对象在配置文件中必须是唯一的
# 不唯一,它怎么知道给你注入哪一个?
<bean id="" class="" autowire="byType"/>
  • 依赖自动装配特征
    • 自动装配用于引用类型依赖注入,不能对简单类型进行操作
    • 使用按类型装配时(byType)必须保障容器中相同类型的bean唯一,推荐使用
    • 使用按名称装配时(byName)必须保障容器中具有指定名称的bean,因变量名与配置耦合,不推荐使用
    • 自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效

集合注入

<bean id="" class="">
	<property name="array">
		<array>
			<value>100</value>
			<value>30</value>
			<ref bean="beanId"/> # 引用类型
		</array>
	</property>
	<property name="list">
	 	<list>
	 		<value>adjkl</value>
	 		<value>30</value>
	 	</list>
 	</property>
 	<property name="list">
	  	<set>
	  		<value>adjkl</value>
	  		<value>30</value>
	  	</set>
  	</property>
  	<property name="list">
	   	<map>
	   		<entry key="name" value="zhangsan"/>
	   		<entry key="" value=""/>
	   	</map>
   </property>
   <property name="properties">
    	<props>
    		<prop key="key">value</prop>
    		<prop key="key">value</prop>
    	</props>
   </property>
</bean>

加载properties文件

  1. 开启context命名空间
  2. 使用context空间加载properties文件(加载的文件从resources目录中寻找)
  3. 使用属性占位符:${}读取properties文件中的属性
<?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"
       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,把两行末尾的beans更换为context
       http://www.springframework.org/schema/context 
       http://www.springframework.org/schema/context/spring-context.xsd
       ">  

	# 1.开启context命名空间
	2.使用context空间加载properties文件(加载的文件从resources目录中寻找)
	# 3. 使用属性占位符:${}读取properties文件中的属性
	<context:property-placeholder location="resources目录下的properties文件"/>
	
    <bean id="service" class=
    "com.fyislo.service.Impl.BookServiecImpl">
        <property name="url" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.user}"/>  
    </bean>  
</beans>

加载properties文件

image.png

依赖注入相关

image.png

容器

创建容器

1、加载类路径下的配置文件

//加载类路径下的配置文件
ApplicationContext act =  new ClassPathXmlApplicationContext("applicationContext.xml");

2、从文件系统下加载配置文件

//从文件系统下加载配置文件
ApplicationContext act = new FileSystemXmlApplicationContext("C:\software\project\JavaProject\JavaStudy\src\main\resources\applicationContext.xml");

加载bean的方式

# 根据名称获取bean,需要强转
BookService bookService = (BookService) act.getBean("service");

# 根据名称获取bean,不需要强转
BookService bookService = act.getBean("service",BookService.class);

# 根据类型获取bean
BookService bookService = act.getBean(BookService.class);

# 加载多个配置文件
ApplicationContext act =  new ClassPathXmlApplicationContext("bean1.xml","bean2.xml");

ApplicationContext 的顶层接口是 BeanFactory ,它也可以创建IoC容器,但存在局限性。

  • ApplicationContextBeanFactory 的区别
    • 它们加载bean的时机不同
      • ApplicationContext 是启动容器后立即加载
      • BeanFactory 是延迟加载

如果需要 ApplicationContext 完成延时加载,可以给 bean 标签添加一个属性 lazy-init="true"

image.png

免责声明:此片文章是个人学习笔记,存在借鉴,若有冒犯或侵权,联系可删除。

posted @ 2024-05-01 17:56  不柴  阅读(35)  评论(0编辑  收藏  举报