1. 什么是Bean标签
其实在上一章我们已经使用Bean标签,它就是标识那些对象需要交给Spring容器管理,以及设置Bean的相关属性。
2. 带着疑问阅读
- bean标签如何使用?
- bean标签是如何加载的?
- bean标签有那些属性?
- 什么是懒加载?
- bean标签在容器中体现的形式是什么?
3.基础使用
要学习新的一个知识点,我们第一步需要先让其先跑起来,我再来研究它的属性。
创建一个spring管理的bean
public class UserService{
public String getName(){
return "张三";
}
}
创建一个application.xml(名字无所是什么)文件,并且将其放在resource目录下
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userService" class="com.qiupeng.bean.ioc.service.UserService"/>
</beans>
创建一个测试类
public class BeanTest(){
public static void main(String[] arg){
ApplicationContext = context = new ClassPathXmlApplicationContext("classpath:application.xml");
UserService userService = context.getBean("userService",UserService.class);
System.out.printfln(userService.getName());
}
}
最终输出
张三
通过上述代码,以及使用了最简化Bean标签,将对象交给了容器进行管理了。
3. Bean标签属性使用和说明
属性 | 说明 |
---|---|
id | 当前bean在容器中的唯一标识,该值不允许重复,建议使用类名首字母小写进行设置,比如类名是UserService那么id就设置为userService |
class | 设置需要管理bean的class全路径 |
scope | 当前实例化bean的作用域 |
constructor-arg | 设置有参构造函数的注入参数 |
properties | 通过set方法进行属性注入 |
autowire | 属性自动注入方式 |
lazy-init | 是否为懒加载bean |
init-method | bean初始化掉调用 |
destroy-method | bean销毁时调用 |
bean标签中大体可以分为两类,bean基础配置和bean的属性注入,本章中我们先了解一下bean基础配置的属性。
3.1. id
该属性在第一个例子以及进行了演示,就是给注入的bean设置一个ID属性,并且该id不允许重复,在使用ApplicationContext可以通过该Id属性进行获取bean.
3.2. class
该属性在第一个例子以及进行了演示,该属性就是设置当前bean的class全路径,Spring通过该属性进行构建bean对象。
3.3. scope
该属性时标识bean的作用域,默认设置的是singleton代表是单例的意思,该属性还可以设置为prototype、request、session、application、websocket,其中常用的就是singleton和prototype(多例模式)。
创建两个java类
public class PrototypeModel{
}
public class SingletonModel{
}
修改xml文件
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 单例的bean -->
<bean id="singletonModel" class="com.qiupeng.bean.ioc.model.SingletonModel"/>
<!-- 多例的bean -->
<bean id="prototypeModel" class="com.qiupeng.bean.ioc.model.PrototypeModel" scope="prototype" />
</beans>
创建一个测试类
public class BeanIocTest {
public static void main(String[] arg) {
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
for (int i = 0; i < 10; i++) {
PrototypeModel prototypeModel = context.getBean("prototypeModel", PrototypeModel.class);
SingletonModel singletonModel = context.getBean("singletonModel", SingletonModel.class);
System.out.println("prototypeModel:" + prototypeModel);
System.out.println("singletonModel:" + singletonModel);
System.out.println("-----------------------------------------");
}
}
}
最终输出
prototypeModel:com.qiupeng.bean.ioc.model.PrototypeModel@58be6e8
singletonModel:com.qiupeng.bean.ioc.model.SingletonModel@7331196b
-----------------------------------------
prototypeModel:com.qiupeng.bean.ioc.model.PrototypeModel@3f9342d4
singletonModel:com.qiupeng.bean.ioc.model.SingletonModel@7331196b
-----------------------------------------
prototypeModel:com.qiupeng.bean.ioc.model.PrototypeModel@ab7395e
singletonModel:com.qiupeng.bean.ioc.model.SingletonModel@7331196b
-----------------------------------------
prototypeModel:com.qiupeng.bean.ioc.model.PrototypeModel@50d13246
singletonModel:com.qiupeng.bean.ioc.model.SingletonModel@7331196b
-----------------------------------------
prototypeModel:com.qiupeng.bean.ioc.model.PrototypeModel@2bd08376
singletonModel:com.qiupeng.bean.ioc.model.SingletonModel@7331196b
-----------------------------------------
prototypeModel:com.qiupeng.bean.ioc.model.PrototypeModel@e70f13a
singletonModel:com.qiupeng.bean.ioc.model.SingletonModel@7331196b
-----------------------------------------
prototypeModel:com.qiupeng.bean.ioc.model.PrototypeModel@3d3e5463
singletonModel:com.qiupeng.bean.ioc.model.SingletonModel@7331196b
-----------------------------------------
prototypeModel:com.qiupeng.bean.ioc.model.PrototypeModel@64a40280
singletonModel:com.qiupeng.bean.ioc.model.SingletonModel@7331196b
-----------------------------------------
prototypeModel:com.qiupeng.bean.ioc.model.PrototypeModel@4b40f651
singletonModel:com.qiupeng.bean.ioc.model.SingletonModel@7331196b
-----------------------------------------
prototypeModel:com.qiupeng.bean.ioc.model.PrototypeModel@42b02722
singletonModel:com.qiupeng.bean.ioc.model.SingletonModel@7331196b
-----------------------------------------
观察输出结果可以看出,单例对象每次获取的都是获取的是同一个对象,而多例模式每次获取到的不通的对象。
3.4. lazy-init
该属性默认为false,而且该属性只有标识单例模式的对象才会有效果,因为多例对象在初始化容器后是不会创建(后面源码理解章节会进步介绍)。
为了测试懒加载,创建一个懒加载的类
public class LazyModel{
}
修改xml文件
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 单例的bean -->
<bean id="singletonModel" class="com.qiupeng.bean.ioc.model.SingletonModel"/>
<!-- 多例的bean -->
<bean id="prototypeModel" class="com.qiupeng.bean.ioc.model.PrototypeModel" scope="prototype" />
<!-- 懒加载 -->
<bean id="lazyModel" class="com.qiupeng.bean.ioc.model.LazyModel" lazy-init="true" />
</beans>
修测试类
public class BeanIocTest {
public static void main(String[] arg) {
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
for (int i = 0; i < 10; i++) {
PrototypeModel prototypeModel = context.getBean("prototypeModel", PrototypeModel.class);
SingletonModel singletonModel = context.getBean("singletonModel", SingletonModel.class);
System.out.println("prototypeModel:" + prototypeModel);
System.out.println("singletonModel:" + singletonModel);
System.out.println("-----------------------------------------");
}
}
}
通过debug方式来查看容器存在那些bean对象。
通过上图可以看见在容器创建完成后,注入的bean对象只有SingletonModel生效了,其他两个都没有生效,说明在容器创建完成后,懒加载和多例的bean对象都是没有被创建的。
将代码执行过getBean后,发现容器中已经存在了LazyModel这个对象,所有我们可以下结论为,懒加载对象在我们需要使用的时候才会被创建。
3.5. init-method
该数据设置一个函数名称,在bean对象创建时会自动调用该函数。
添加前置函数
在SingletonModel类中添加一个init的函数(名称可以随便取)。
public void init() {
System.out.println("调用singletonModel的init函数");
}
修改application.xml
修改xml,在bean的标签中添加init-method的属性,并且设置为init。
<bean id="singletonModel" class="com.qiupeng.bean.ioc.model.SingletonModel" init-method="init" />
测试结果
运行测试函数,通过查看日志可以发现输出了调用singletonModel的init函数
调用singletonModel的init函数
3.6. destroy-method
destroy-method和init-method编写方式一样的,这里就不进行演示了。但是destroy-method函数调用是在bean销毁的时候触发。
4.总结
- 使用< bean>标签就是能实现bean注入。
- bean标签加载流程,xml=>XmlBeanDefinitionReader=>BeanDefinition =>ApplicationContext=>bean.
- 该文章第3节已经说明了。
- 懒加载是在使用的时候,懒加载只针对单例模式有效。
- bean标签通过XmlBeanDefinitionReader读取后转换成BeanDefinition ,在存入ApplicationContext中。
5.扩展知识
大家可以思考一个问题,当前我们都是把所有bean标签写到一个配置文件中,如果很多bean标签就会导致这个文件很臃肿,其实spring也提供import标签来进行xml拆分。
例子
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 加载外部文件 -->
<import resource="application-dev.xml"/>
</beans>
通过上述例子,就可以使用一个xml来管理所有xml文件,这样就可以分模块来管理xml了。(其实bean标签没有必要这么复杂,后面文章也会介绍扫描方式来扫描bean对象)