spring- IOC: 管理Bean 的生命周期,以及依赖注入。
一、 IOC 核心知识点
-
IOC概要
-
实体Bean 的创建
-
Bean的基本特性
-
依赖注入
-
IOC 概要:
java中,对象A 调用对象B 的几种方法:
上表可以看到, 引用一个对象可以在不同地点(其它引用者)、不同时间由不同的方法完成。如果B只是一个非常简单的对象 如直接new B(),怎样都不会觉得复杂,比如你从来不会觉得创建一个String 是一个件复杂的事情。但如果B 是一个有着复杂依赖的Service对象,这时在不同时机引用B将会变得很复杂。
IOC容器的出现正是为解决这一问题,其可以将对象的构建方式统一,并且自动维护对象的依赖关系,从而降低系统的实现成本。前提是需要提前对目标对象基于XML进行声明。 -
实体Bean 的创建
a. 基于class创建
b. 构造方法创建
c. 静态工厂方法创建
d. FactoryBean创建
-
a . 基于 class创建:
<bean class="com.huonilaifu.spring.User"></bean>
b. 基于构造方法创建
<bean class="com.huonilaifu.spring.User">
<constructor-arg name="name" type="java.lang.String" value="xiaoming"/>
<constructor-arg index="1" type="java.lang.String" value="sex" />
</bean>
name:构造方法参数变量名称
type:参数类型index:参数索引,从0开始
value:参数值,spring 会自动转换成参数实际类型值
ref:引用容串的其它对象
c. 静态工厂方法创建
<bean class="com.huonilaifu.spring.User" factory-method="build">
<constructor-arg name="type" type="java.lang.String" value="B"/>
</bean>
d. FactoryBean 创建:
指定一个Bean工厂来创建实际的Bean
<bean class="com.tuling.spring.DriverFactoryBean">
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306"/>
</bean>
public class DriverFactoryBean implements FactoryBean {
private String jdbcUrl;
public Object getObject() throws Exception {
return DriverManager.getDriver(jdbcUrl);
}
public Class<?> getObjectType() {
return Driver.class;
}
public boolean isSingleton() {
return true;
}
public String getJdbcUrl() {
return jdbcUrl;
}
public void setJdbcUrl(String jdbcUrl) {
this.jdbcUrl = jdbcUrl;
}
}
-
bean 的基本特性:
a. 作用范围
b. 生命周期
c. 装载依赖a、作用范围:
很多时候Bean对象是无状态的 ,而有些又是有状态的 无状态的对象我们采用单例即可,而有状态则必须是多例的模式,通过scope 即可创建scope=“prototype”scope=“singleton”
scope=“prototype
<bean class="com.huonilaifu.spring.User" scope="prototype">
</bean>
如果一个Bean设置成 prototype 我们可以 通过BeanFactoryAware 获取 BeanFactory 对象即可每次获取的都是新对像。
b. 生命周期:
Bean对象的创建、初始化、销毁即是Bean的生命周期。通过 init-method、destroy-method 属性可以分别指定期构建方法与初始方法。
<bean class="com.huonilaifu.spring.User" init-method="init" destroy-method="destroy">
</bean>
c、加载机制指示Bean在何时进行加载。
设置lazy-init 即可,
其值如下:true: 懒加载,即延迟加载false:非懒加载,容器启动时即创建对象default:默认,采用default-lazy-init 中指定值,如果default-lazy-init 没指定就是false
- 依赖注入
a.set方法注入
b.构造方法注入
c.自动注入(byName、byType)
d.方法注入(lookup-method)
a. set方法注入:
<bean class="com.huonilaifu.spring.User">
<property name="fine" ref="fineSpring"/>
</bean>
b. 构造方法注入
<bean class="com.huonilfaifu.spring.User">
<constructor-arg name="fine">
<bean class="com.huonilaifu.spring.FineSpring"/>
</constructor-arg>
</bean>
c. 自动注入
<bean id="userAutowireConstructor"class="com.huonilaifu.spring.User" autowire="byName">
</bean>
byName:基于变量名与bean 名称相同作为依据插入
byType:基于变量类别与bean 名称作
constructor:基于IOC中bean 与构造方法进行匹配(语义模糊,不推荐)
d. 依赖方法注入(lookup-method)
当一个单例的Bean,依赖于一个多例的Bean,用常规方法只会被注入一次,如果每次都想要获取一个全新实例就可以采用lookup-method 方法来实现。
#编写一个抽像类
public abstract class MethodInject {
public void handlerRequest() {
// 通过对该抽像方法的调用获取最新实例
getFine();
}
# 编写一个抽像方法
public abstract FineSpring getFine();
}
// 设定抽像方法实现
<bean id="MethodInject" class="com.huonilaifu.spring.MethodInject">
<lookup-method name="getFine" bean="fine"></lookup-method>
</bean>
该操作的原理是基于动态代理技术,重新生成一个继承至目标类,然后重写抽像方法到达注入目的。前面说所单例Bean依赖多例Bean这种情况也可以通过实现 ApplicationContextAware 、BeanFactoryAware 接口来获取BeanFactory 实例,从而可以直接调用getBean方法获取新实例,推荐使用该方法,相比lookup-method语义逻辑更清楚一些
二、 IOC 设计原理及实现
Bean工厂是如何生产Bean的?
Bean的依赖关系是由谁解来决的?
Bean工厂和应用上文的区别?
-
Bean的构建过程
spring.xml 文件中保存了我们对Bean的描述配置,BeanFactory 会读取这些配置然后生成对应的Bean。 -
BeanDefinition :Bean信息的承载对象,与spring 中bean是一一对应的关系。
xml bean中设置的属性最后都会体现在BeanDefinition中。如:
-
BeanDefinitionRegistry (bean 注册器):
在上表中我们并没有看到 xml bean 中的 id 和name属性没有体现在定义中,原因是ID 其作为当前Bean的存储key注册到了BeanDefinitionRegistry 注册器中。name 作为别名key 注册到了 AliasRegistry 注册中心。其最后都是指向其对应的BeanDefinition -
BeandefinitionReader :读取器
BeanDefinition 中存储了Xml Bean信息,而BeanDefinitionRegister 基于ID和name 保存了Bean的定义。从xml Bean到BeanDefinition 然后在注册至BeanDefinitionRegister 整个过程
上图中可以看出Bean的定义是由BeanDefinitionReader 从xml 中读取配置并构建出BeanDefinitionReader,然后在基于别名注册到BeanDefinitionRegister中。 -
实例演示 装载bean
/创建一个简单注册器
BeanDefinitionRegistry register = new SimpleBeanDefinitionRegistry();
//创建bean定义读取器
BeanDefinitionReader reader = new XmlBeanDefinitionReader(register);
// 创建资源读取器
DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
// 获取资源
Resource xmlResource = resourceLoader.getResource("spring.xml");
// 装载Bean的定义
reader.loadBeanDefinitions(xmlResource);
// 打印构建的Bean 名称
System.out.println(Arrays.toString(register.getBeanDefinitionNames());
-
BeanFactory Bean 工厂
有了Bean的定义就相当于有了产品的配方,接下来就是要把这个配方送到工厂进行生产了。在ioc当中Bean的构建是由BeanFactory 负责的。
方法说明: -
getBean(String)基于ID或name 获取一个Bean
-
T getBean(Class requiredType) 基于Bean的类别获取一个Bean(如果出现多个该类的实例,将会报错。但可以指定primary=“true” 调整优先级来解决该错误
-
Object getBean(String name, Object… args)基于名称获取一个Bean,并覆盖默认的构造参数
-
boolean isTypeMatch(String name, Class<?> typeToMatch)指定Bean与指定Class 是否匹配
-
演示基本BeanFactory获取一个Bean
#创建Bean堆栈
// 其反射实例化Bean
java.lang.reflect.Constructor.newInstance(Unknown Source:-1)
BeanUtils.instantiateClass()
//基于实例化策略实例化Bean
SimpleInstantiationStrategy.instantiate()
AbstractAutowireCapableBeanFactory.instantiateBean()
// 执行Bean的实例化方法
AbstractAutowireCapableBeanFactory.createBeanInstance()
AbstractAutowireCapableBeanFactory.doCreateBean()
// 执行Bean的创建
AbstractAutowireCapableBeanFactory.createBean()
// 缓存中没有,调用指定Bean工厂创建Bean
AbstractBeanFactory$1.getObject()
// 从单例注册中心获取Bean缓存
DefaultSingletonBeanRegistry.getSingleton()
AbstractBeanFactory.doGetBean()
// 获取Bean
AbstractBeanFactory.getBean()
从调用过程可以总结出以下几点:
1.调用BeanFactory.getBean() 会触发Bean的实例化。
2 DefaultSingletonBeanRegistry 中缓存了单例Bean
3.Bean的创建与初始化是由AbstractAutowireCapableBeanFactory 完成的
- BeanFactory 与 ApplicationContext区别
可以看到 ApplicationContext 它由BeanFactory接口派生而来,因而提供了BeanFactory所有的功能。除此之外context包还提供了以下的功能:
1.MessageSource, 提供国际化的消息访问
2.资源访问,如URL和文件
3.事件传播,实现了ApplicationListener接口的bean
4.载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层