1.5 Spring IOC的原理
1.5.1 Spring IOC简介
Spring通过一个配置文件描述Bean与Bean之间的依赖关系,利用Java的反射功能实例化Bean并建立Bean之间的关系。Spring的IOC容器在完成这些底层工作的基础上,还提供了Bean实例缓存管理、Bean实例代理、
事件发布和资源装配等高级服务。
1.5.2 Sprng Bean的装配流程
Spring 在启动时会从XML配置文件或注解中读取应用程序提供的Bean配置信息,并在Spring容器中生成一份相应的Bean配置注册表;然后根据这张注册表实例化Bean,装配好Bean之间的依赖关系,为上层业务提供基础的运行
环境。其中Bean缓存池为HashMap实现。Spring Bean的装配流程如图1-3所示:
1.5.3 Spring Bean的作用域
Spring 为Bean定义了5种作用域,分别是Singleton(单例)、Prototype(原型)、Request(请求级别)、Session(会话级别)和Global Session(全局会话)。
1. Singleton
Singleton 是单例模式,当实例类型为单例模式时,Spring IOC容器只会存在一个共享的Bean的实例,无论有多少个Bean引用它,都始终指向同一个Bean对象.该模式在多线程下
是安全的。Singleton作用域是Spring中的默认作用域,也可以通过配置将Bean定义为Singleton模式,具体配置如下:
<bean id=userDao" class="com.alex.UserDaoImpl" scope="singleton"/>
2.Prototype
Prototype是原型模式,每次通过Spring容器获取Prototype定义的Bean时,容器都将创建一个新的Bean实例,每个Bean实例都有自己的属性和状态,而Singleton全局只有一个对象。因此,对有状态的Bean经常使用Prototype
作用域,而对于无状态的Bean,则使用Singletion作用域。具体配置如下。
<bean id="userService" class="com.alex.UserService" scope="prototype"/>
3.Request
Request指在一次HTTP请求中容器会返回该Bean的同一个实例,而对不同的HTTP请求则不会创建新的Bean实例,并且该Bean实例仅在当前HTTP请求内有效,当前HTTP请求结束后,该Bean实例也将会随之被销毁。具体配置如下:
<bean id="loginAction" class="com.alex.Login" scope="Request"/>
4.Session
Session指在一次HTTP Session中容器会返回该Bean的同一个实例,而对不同的Session请求则会创建新的Bean实例,该Bean实例仅在当前Session内有效。和HTTP请求相同,每一次Session都会创建新的Bean实例,而不同的Bean
实例之间不共享数据,且Bean实例仅在自己的Session内有效,请求结束,这Bean实例将随之被销毁。具体配置如下.
<bean id="userSession" class="com.alex.UserSession" scope="session"/>
5.Global Sesssion
Global Session指在一个全局的HTTP Session中容器会返回该Bean的同一个实例,且仅在使用Product Context时有效。
1.5.4 Spring Bean的生命周期
Spring Bean的生命周期执行过程如图下所示:
(1)实例化一个Bean
(2)按照Spring上下文对实例化的Bean进行配置
(3)如果这个Bean实现了BeanNameAware接口,则会调用它实现的setBeanName(String)方法,该方法传递的参数是Spring配置文件中Bean的id值。
(4)如果这个Bean实现了ApplicationContextAware接口,则会调用它实现的setBeanFactory(BeanFactory)方法,该方法传递的参数是Spring工厂自身。
(5)如果这个Bean实现了ApplicationContextAware接口,则会调用setApplication(ApplicationContext)方法,该方法传递的参数是Spring工厂自身
(6)如果该Bean关联了BeanPostProcess接口,则会调用postProcessBeforeInitalization(Object obj,String s)方法,该方法在Bean初始化前调用,常用于定义初始化Bean的前置工作,比如系统缓存的初始化。
(7)如果Bean在Spring 配置文件中配置了init-method属性,则会调用其配置的初始化方法。
(8)如果某个bean关联了BeanPostProcess接口,将会调用postProcessAfterInitalization(Object obj,String s)方法。至此,bean的初始化工作就完成了,应用程序就可以开始使用Bean实例了。
(9)当Bean不再被需要时,会在清理阶段被清理掉。如果Bean实现了DisposableBean接口,则Spring会在退出前调用实现类的destroy()方法.
(10)如果某个Bean的Spring配置文件中配置了destroy-method属性,在Bean被销毁前会自动调用其配置的销毁方法。
1.5.5 Spring 的4种依赖注入
(1)构造器注入
构造器注入指通过在类的构造函数中注入属性或对象来实现依赖注入。如下代码通过
注入了一个message属性,注入完成后在类中可以直接通过this.message获取注入的属性值。
// 在构造函数中注入message属性
public PersionDaoImpl (String message){
this.message = message;
}
<!-- 定义bean实例并在构造函数(constructor-arg)中注入message属性-->
<bean id="persionDaoImpl" class="com.PersionDaoImpl">
<constructor-arg value="message"></constructure>
</bean>
2.set方法注入
set方法注入是通过在类中实现get、set方法来实现属性或对象的依赖注入的。如下代码通过
后在类中可以直接使用getId()获取注入的属性。
public class PersionDaoImpl{
private int id; // 定义属性和其对应的get、set方法
private int getId(){
return id;
}
public void setId(int id){
this.id = id;
}
<!--定义Beana实例并通过property注入id为123的属性值-->
<bean id="persionDaoImpl" class="com.PersionDaoImpl">
<property name="id" value="123"></property>
<bean>
3.静态工厂注入
静态工厂注入是通过调用工厂类中定义的静态方法来获取需要的对象的,为了让Spring管理所有对象,应用程序不能直接通过"工厂类.静态方法()"的方式获取对象,而需要通过Spring注入的方式获取.代码如下。
public class DaoFactory{ //1:定义静态工厂
public static final FactoryDao getStaticFactoryDaoImpl(){
return new StaticFacotryDaoImpl();
}
}
public class SpringAction{
private FactoryDao staticFactoryDao; // 2.定义工厂对象
//3.注入工厂对象
public void setStaticFactoryDao(FactoryDao staticFactoryDao){
this.staticFactoryDao = staticFactoryDao;
}
}
上述代码定义了一个DaoFactory工厂类和getStaticFactoryDaoImpl()静态工厂方法,该方法实例化并返回一个StaticFactoryDaoImpl实例;同时定义了一个SpringAction类,并通过setStaticFactoryDao获取注入的FactoryDao.具体的XML注入语法如下:
<!--1.定义获取工厂对象的静态方法-->
<bean name="staticFactoryDao" class="DaoFactory"
factory-method="getStaticFactoryDaoImpl">
</bean><!--factory-method="getStaticFactoryDaoImpl"用于指定调用哪个工厂方法-->
<bean name="springAction" class="SpringAction">
<!--2.注入静态工厂实例-->
<property name="staticFactoryDao" ref="staticFactoryDao"></property>
</bean>
上述代码定义了一个name为staticFactoryDao的工厂类,并通过factory-method定义了实例化对象的方法,这里实例化对象的方法是一个名为getStaticFactoryDaoImpl的静态方法.该静态方法返回一个工厂类实例,在springAction中通过
1.5.6 自动装配的5种方式
Spring的装配方式包括手动装配和自动装配。手动装配包括基于XML装配(构造器方法、set方法等)和基于注解装配2种方式。自动装配包括5种装配方式,这5种装配方式均可以用来引导Spring容器自动完成依赖注入,具体如下:
(1)no:关闭自动装配
(2)byName:通过参数名自动装配,Bean的autowire被设置为byName后,Spring容器试图匹配并装配与该Bean的属性具有相同名字的Bean.
(3)byType:通过参数类型自动装配,Bean的autowire被设置为byType后,Spring容器试图匹配并装配与该Bean的属性具有相同类型的Bean
(4)constructor:通过设置构造器参数的方式来装配对象,如果没有匹配到参数的构造器参数类型,则Spring会抛出异常。
(5)autodetect:首先尝试使用constructor来自动装配,如果无法完成自动装配,则使用byType方式进行装配。