Spring容器就是一个超级大工厂,Spring容器中的Bean就是该工厂的产品。
对于开发者来说,Spring框架主要是做两件事:
(1)开发Bean
(2)配置Bean
1. Bean的定义和Bean别名
bean 是一个被实例化,组装,并通过 Spring IoC 容器所管理的对象。
它是由容器提供的配置元数据创建的。
Bean定义包含称为配置元数据的信息,需要知道:
- 如何创建一个Bean;
- Bean的生命周期的详细信息;
- Bean的依赖关系。
元数据:描述数据的数据,比如表的列名,< bean>的参数等都算,都用于描述数据和对象的数据。
姓名
张三
李四
王五
2. Bean与Spring容器的关系
下图表达了Bean与Spring容器之间的关系:
Spring配置元数据
Spring容器完全由实际编写的配置元数据的格式解耦。有三种方法把配置元数据提供给Spring容器:
- 基于XML的配置;
- 基于注解的配置;
- 基于Java的配置(配置类)。
示例1:基于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
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="user" class="cn.zhibang.User"></bean>
<!-- 匿名bean -->
<bean class="cn.zhibang.User"></bean>
<!-- 初始化时懒加载(延迟加载) -->
<bean id="..." class="..." lazy-init="true"></bean>
<!-- 指定Bean初始化时调用的方法 -->
<bean id="..." class="..." init-method="..."></bean>
<!-- 指定Bean销毁时调用的方法 -->
<bean id="..." class="..." destroy-method="..."></bean>
</beans>
3. Bean定义中的id与name
3.1. id属性
Spring容器管理的Bean中,id是唯一标识,不能出现两个相同名称的id。
<bean id="user" class="com.alibaba.model.User"></bean>
如果Spring容器管理的Bean中出现相同的id时:
- 如果Spring是默认设置,则同名的Bean会出现后面覆盖前面的现象,且不会报异常。
- 如果Spring设置同id不能覆盖,则会抛出异常,停止运行。
3.2. name属性
如果一个bean只配置了name属性,但没有配置ID属性,默认会是ID属性=name属性。
<bean name="user" class="com.alibaba.model.User"></bean>
这里的name=”user”相当于 id=”user” name=”user”。
注意:可以存在同名的< bean>???。
但下列情况,后面的会覆盖前面的:
<bean name="user" class="com.alibaba.model.User"></bean>
<bean id="user" class="com.alibaba.model.User"></bean>
3.3. 匿名
<bean class="com.alibaba.model.User"></bean>
未给Bean设置名称,当在使用时会报异常:
4.Bean作用域
在Spring定义一个bean时,可以设置scope属性来声明该bean的作用域:
<bean id="..." class="..." scope="singleton">
……
</bean>
Spring框架支持以下五个作用域:
作用域 | 描述 |
---|---|
singleton | 默认值,单例模式,在Spring IOC容器中,Bean实例将只生成一个实例。 |
prototype | 每次从容器中调用Bean时getBean(),都返回一个新的实例,即每次调用getBean()时,相当于执行new XxxBean() |
request | 每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境 |
session | 同一个HTTP Session共享一个Bean,不同Session使用不同的Bean,仅适用于WebApplicationContext环境 |
global-session | 一般用于Portlet应用环境,改作用于仅适用于WebApplicationContext环境 |
5.Bean生命周期
Spring Bean的生命周期是指:
当一个bean被实例化时,它需要执行初始化方法,让bean转换成可用状态。
同样,当bean不再需要时,从容器中移除(销毁方法)。
Spring容器可以管理Singleton作用域的生命周期,Spring容器可以精确的知道该Bean何时被创建、何时被初始化完成、容器何时准备销毁该Bean实例。
而对于prototype作用域的Bean,Spring容器仅仅负责创建,当创建后交给客户端代码管理,Spring容器不再跟踪其生命周期。
管理Bean的生命周期行为主要有如下两个时机:
- 注入依赖关系之后(初始化回调)
- 即将销毁Bean之前(销毁回调)
5.1. 注入依赖关系之后(初始化回调)
Spring提供两种方式在Bean全部属性设置成功后执行特定行为。
- 使用init-method属性
<bean id="userBean" class="com.alibaba.model.UserBean" init-method="init"/>
类的定义:
public class UserBean {
//初始化方法
public void init() {
System.out.println("实例化即执行了初始化方法...");
}
}
当项目启动时,加截applicationContext.xml实例化一个个的Bean,当实例化UserBean时,执行init(),输出“实例化即执行了初始化方法…”
- 实现InitializingBean接口(不建议使用)
public class ExampleBean implements InitializingBean {
//重写方法完成初始化
public void afterPropertiesSet() {
}
}
5.2. 即将销毁Bean之前(销毁回调)
- 使用destory-method属性
<bean id="userBean" class="com.alibaba.model.UserBean" destroy-method="destroy"/>
类的定义:
public class UserBean {
public void destroy() {
System.out.println("执行销毁的方法。。。")
}
}
- 实现DisposableBean接口(不建议使用)
public class UserBean implements DisposableBean {
public void destroy() {
}
}
5.3. 关闭hook
在非Web应用序中使用Spring IOC容器,则要注册关闭hook。这样可以确保正常关闭,释放所有资源。
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
obj.getMessage();
context.registerShutdownHook();
}
5.4. 默认的初始化和销毁方法
如果众多Bean的初始化方法或销毁方法相同,则不需要为每个Bean配置初始化方法和销毁方法,在中配置默认初始化和销毁方法即可。
<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-3.0.xsd"
default-init-method="init"
default-destroy-method="destroy">
<bean id="..." class="..." init-method=”init” destory-method=”destroy”>
</bean>
<bean id="..." class="..." init-method=”init” destory-method=”destroy>
</bean>
</beans>
6. Bean后置处理器
6.1. Bean定义继承
HelloWorld类的定义:
public class HelloWorld {
private String message1;
private String message2;
public void setMessage1(String message){
this.message1 = message;
}
public void setMessage2(String message){
this.message2 = message;
}
public void getMessage1(){
System.out.println("World Message1 : " + message1);
}
public void getMessage2(){
System.out.println("World Message2 : " + message2);
}
}
HelloIndia类的定义:
public class HelloIndia {
private String message1;
private String message2;
private String message3;
public void setMessage1(String message){
this.message1 = message;
}
public void setMessage2(String message){
this.message2 = message;
}
public void setMessage3(String message){
this.message3 = message;
}
public void getMessage1(){
System.out.println("India Message1 : " + message1);
}
public void getMessage2(){
System.out.println("India Message2 : " + message2);
}
public void getMessage3(){
System.out.println("India Message3 : " + message3);
}
}
Bean配置文件:
<?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-3.0.xsd">
<bean id="helloWorld" class="com.alibaba.model.HelloWorld">
<property name="message1" value="Hello World!"/>
<property name="message2" value="Hello Second World!"/>
</bean>
<!-- 让helloIndia继承helloWorld -->
<bean id="helloIndia" class="com.alibaba.model.HelloIndia" parent="helloWorld">
<property name="message1" value="Hello India!"/>
<property name="message3" value="Namaste India!"/>
</bean>
</beans>
测试:
@Test
public void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
HelloWorld objA = (HelloWorld) context.getBean("helloWorld");
objA.getMessage1();
objA.getMessage2();
HelloIndia objB = (HelloIndia) context.getBean("helloIndia");
objB.getMessage1();
objB.getMessage2();
objB.getMessage3();
}
结果:
World Message1 : Hello World!
World Message2 : Hello Second World!
India Message1 : Hello India!
India Message2 : Hello Second World!
India Message3 : Namaste India!
7. 通过maven引入Spring依赖坐标
仅需在pom.xml中引入spring-context包即可。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.8.RELEASE</version>
</dependency>
8. Spring工具插件安装(Eclipse)
Spring插件:Spring TOOL
作用:方便创建spring的xml文件
在线安装步骤:Help -> Eclipse Marketplace… -> 搜索 spring tool -> 找到后install即可。