文章目录
- 配置标签
- `<beans>`标签
- `<import>`标签
- `<alias>` 标签
- 自定义标签
- Bean
- Bean 常用配置
- Bean 作用域
- Bean 实例化流程
- Bean 生命周期
配置标签
Spring 的 xml 标签大体上分为两类,一种是默认标签,一种是自定义标签
默认标签:就是不用额外导入其他命名空间约束的标签,例如 <bean>
标签
自定义标签:就是需要额外引入其他命名空间约束,并通过前缀引用的标签,例如 <context:propert-placeholder/>
标签
标签 | 作用 |
---|---|
<beans> | 一般作为 xml 配置根标签,其他标签都是该标签的子标签 |
<bean> | Bean的配置标签,上面已经详解了,此处不再阐述 |
<import> | 外部资源导入标签 |
<alias> | 指定Bean的别名标签,使用较少 |
<beans>
标签
除了经常用的做为根标签外,还可以嵌套在根标签内,使用profile属性切换开发环境
<!-- 配置测试环境下,需要加载的Bean实例 -->
<beans profile="test"></beans>
<!-- 配置开发环境下,需要加载的Bean实例 -->
<beans profile="dev"></beans>
可以使用以下两种方式指定被激活的环境:
- 使用命令行动态参数,虚拟机参数位置加载
-Dspring.profiles.active=test
- 使用代码的方式设置环境变量
System.setProperty("spring.profiles.active","test")
<import>
标签
用于导入其他配置文件,项目变大后,就会导致一个配置文件内容过多,可以将一个配置文件根据业务某块进行拆分,拆分后,最终通过<import>标签导入到一个主配置文件中,项目加载主配置文件就连同<import> 导入的文件一并加载了
<!--导入用户模块配置文件-->
<import resource="classpath:UserModuleApplicationContext.xml"/>
<!--导入商品模块配置文件-->
<import resource="classpath:ProductModuleApplicationContext.xml"/>
<alias>
标签
为某个Bean添加别名,与在<bean> 标签上使用name属性添加别名的方式一样
<!--配置UserService-->
<bean id="userService" name="aaa,bbb" class="com.itheima.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao"/>
</bean>
<!--指定别名-->
<alias name="userService" alias="xxx"/>
<alias name="userService" alias="yyy"/>
自定义标签
Spring的自定义标签需要引入外部的命名空间,并为外部的命名空间指定前缀,使用 <前缀:标签> 形式的标签,称之为自定义标签,自定义标签的解析流程也是 Spring xml扩展点方式之一。(引入命名空间和文件映射地址)
<!--默认标签-->
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
<!--自定义标签-->
<context:property-placeholder/>
<mvc:annotation-driven/>
<dubbo:application name="application"/>
Bean
Bean 就是由 Spring IoC 容器实例化、组装和管理的对象。Spring 通过配置文件(如XML文件)或注解来定义 Bean,并利用这些信息来创建和管理应用程序中的对象及其依赖关系。定义方式:
- XML配置:在XML配置文件中使用
<bean>
标签来定义一个Bean。 - Java配置:基于Java的配置方式,即通过
@Configuration
类配合@Bean
注解来定义Bean。
Bean 常用配置
Xml配置方式 | 功能描述 |
---|---|
<bean id=“” class=“”> | Bean的id和全限定名配置 |
<bean name=“”> | 通过name设置Bean的别名,通过别名也能直接获取到Bean实例 |
<bean scope=“”> | Bean的作用范围,BeanFactory作为容器时取值singleton和prototype |
<bean lazy-init=“”> | Bean的实例化时机,是否延迟加载。BeanFactory作为容器时无效 |
<bean init-method=“”> | Bean实例化后自动执行的初始化方法,method指定方法名 |
<bean destroy-method=“”> | Bean实例销毁前的方法,method指定方法名 |
<bean autowire=“byType”> | 设置自动注入模式,常用的有按照类型byType,按照名字byName |
<bean factory-bean=“” factory-method=“”/> | 指定哪个工厂Bean的哪个方法完成Bean的创建 |
Bean 作用域
定义了 Spring 容器如何创建和管理 Bean 的实例。Spring 提供了多种作用域来控制不同场景下的对象生命周期。
作用域 | 说明 |
---|---|
singleton | 默认值。Spring以单例模式创建Bean的实例,即容器中该Bean的实例只有一个 |
prototype | 每次从容器中获取Bean时,都会创建一个新的实例 |
request | 用于Web应用环境,针对每次HTTP请求都会创建一个实例 |
session | 用于Web应用环境,同一个会话共享同一个实例,不同的会话使用不同的实例 |
global session | 仅在Portlet的Web应用中使用,同一个全局会话共享一个实例。对于非Portlet环境,等同于session |
<bean id="user" class="cn.hz.pojo.User" scope="singleton"/>
<bean id="user" class="cn.hz.pojo.User" scope="prototype"/>
默认情况下,单纯的Spring环境Bean的作用范围有两个
singleton:单例,默认值,Spring容器创建的时候,就会进行Bean的实例化,并存储到容器内部的单例池中,每次getBean时都是从单例池中获取相同的Bean实例;
prototype:原型,Spring容器初始化时不会创建Bean实例,当调用getBean时才会实例化Bean,每次getBean都会创建一个新的Bean实例。
使用 @Scope("prototype")
注解指定 Bean 的作用域
@Scope("prototype")
@Service("userService")
public class UserServiceImpl implements UserService {// 省略其他代码
}
Bean 实例化流程
Spring 容器在进行初始化时,会将 xml 配置的 <bean>
的信息封装成一个 BeanDefinition 对象,所有的 BeanDefinition
存储到一个名为 beanDefinitionMap
的 Map 集合中去,Spring 框架在对该 Map 进行遍历,使用反射创建 Bean 实例对象,创建好的 Bean 对象存储在一个名为 singletonObjects
(单例池)的 Map 集合中,当调用 getBean 方法时则最终从该 Map 集合中取出 Bean 实例对象返回。
<bean id="" class="" name="" lazy-init="" scope="" init-method="" destroy-method="" factory-bean="" factory-method="" abstract="" depends-on="" parent=""><property name="" ref=""/><property name="" ref=""/><property name="" value=""/>
</bean>
public interface BeanDefinition {String SCOPE_SINGLETON = "singleton";String SCOPE_PROTOTYPE = "prototype";void setBeanClassName(@Nullable String var1);String getBeanClassName();void setScope(@Nullable String var1);String getScope();void setLazyInit(boolean var1);boolean isLazyInit();void setFactoryBeanName(@Nullable String var1);String getFactoryBeanName();void setFactoryMethodName(@Nullable String var1);String getFactoryMethodName();void setInitMethodName(@Nullable String var1);String getInitMethodName();//..... 省略部分属性和方法
}
DefaultListableBeanFactory
对象内部维护着一个 Map 用于存储封装好的 BeanDefinitionMap
public class DefaultListableBeanFactory extends ... implements ... {//存储<bean>标签对应的BeanDefinition对象//key:是Bean的beanName,value:是Bean定义对象BeanDefinitionprivate final Map<String, BeanDefinition> beanDefinitionMap;
}
Bean 实例及单例池 singletonObjects
, beanDefinitionMap
中的 BeanDefinition
会被转化成对应的 Bean 实例对象,存储到单例池 singletonObjects
中去,在 DefaultListableBeanFactory
的上四级父类 DefaultSingletonBeanRegistry
中,维护着 singletonObjects
,源码如下:
public class DefaultSingletonBeanRegistry extends ... implements ... {//存储Bean实例的单例池key:是Bean的beanName,value:是Bean的实例对象private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
}
Bean 实例化的基本流程
- 加载 xml 配置文件,解析获取配置中的每个
<bean>
的信息,封装成一个个的BeanDefinition
对象; - 将
BeanDefinition
存储在一个名为beanDefinitionMap
的Map<String,BeanDefinition>
中; ApplicationContext
底层遍历beanDefinitionMap
,创建 Bean 实例对象;- 创建好的 Bean 实例对象,被存储到一个名为
singletonObjects
的Map<String,Object>
中; - 当执行
applicationContext.getBean(beanName)
时,从singletonObjects
去匹配 Bean 实例返回。
Bean 生命周期
Spring Bean 的生命周期是从 Bean 实例化之后,即通过反射创建出对象之后,到 Bean 成为一个完整对象,最终存储到单例池中,这个过程被称为 Spring Bean 的生命周期。Spring Bean 的生命周期大体上分为三个阶段:
- Bean 的实例化阶段:Spring 框架会取出
BeanDefinition
的信息进行判断当前 Bean 的范围是否是singleton
的,是否不是延迟加载的,是否不是FactoryBean
等,最终将一个普通的singleton
的 Bean 通过反射进行实例化; - Bean 的初始化阶段:Bean 创建之后还仅仅是个"半成品",还需要对 Bean 实例的属性进行填充、执行一些 Aware 接口方法、执行
BeanPostProcessor
方法、执行InitializingBean
接口的初始化方法、执行自定义初始化 init 方法等。该阶段是 Spring 最具技术含量和复杂度的阶段:Aop 增强功能,Spring 注解功能、Bean 循环引用问题都是在这个阶段体现的; - Bean 的完成阶段:经过初始化阶段,Bean 就成为了一个完整的 Spring Bean,被存储到单例池
singletonObjects
中去了,即完成了 Spring Bean 的整个生命周期。
Spring Bean 的初始化过程涉及如下几个过程:
- Bean实例的属性填充
- Aware接口属性注入
- BeanPostProcessor的before()方法回调
- InitializingBean接口的初始化方法回调
- 自定义初始化方法init回调
- BeanPostProcessor的after()方法回调