Spring框架是Java应用最广的框架,它的成功来源于理念,而不是技术本身,它的理念包括IoC(Inversion of Control,控制反转)和AOP(Aspect Oriented Programming,面向切面编程)
IoC是一个容器,Spring中,会认为一切Java资源都是Java Bean,容器的目标就是管理这些Bean以及它们之间的关系。所以在Spring Ioc中装载的各种Bean,也可以理解为Java的各种资源,其中包括Java Bean的创建、事件、行为等,它们由IoC容器管理。除此之外,各个Java Bean之间会存在一定的依赖关系,这些也都是IoC容器进行管理。
只是Spring IoC管理对象和其依赖、关系,采用的不是人为的主动创建,而是由Spring IoC自己通过描述创建的,也就是说Spring是依靠描述来完成对象的创建及其依赖关系的。
控制反转的概念:控制反转是一种通过描述(在Java中可以是XML或者注解)并通过第三方去产生或获取特定对象的方式。Spring中实现控制反转的是IoC容器,实现方法是依赖注入(Dependency InJection,DI)
如何理解控制反转,举下面一个例子。榨橙汁,如果是主动地创建,我们需要实现可能不是很熟悉的工作比如搅拌橙汁,而橙汁需要依赖于水,水果,糖和搅拌机去实现,这个关系也需要我们自己去维护。而如果是一个很大的系统,如果都这样维护那么会十分复杂,我们并不需要了解这个过程,我们只需要获取最后的结果。比如由各饮品店,只要对结果进行描述,就能得到我们所需要的饮品。
我们只需要设计好自己的Bean,将Bean添加到IoC容器中,然后构建依赖关系。使用Bean时从IoC容器得到Bean即可。
IoC容器设计
Spring IoC容器的设计主要是基于BeanFactory和ApplicationContext两个接口,BeanFactory是Spring IoC容器所定义的最底层接口,而ApplicationContext是其高级接口之一,并且对BeanFactory功能做了许多有用的扩展,所以在绝大部分的工作场景下,都会使用ApplicationContext作为Spring IoC容器。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hz2uWtkd-1590394435472)(https://note.youdao.com/yws/res/15046/WEBRESOURCE60ff609a3a676db8ed15299cb2ba54d4)]
IoC容器的初始化和依赖注入
Bean的初始化和依赖注入在Spring IoC容器中是两大步骤,它是在初始化之后才会进行依赖注入
Bean的初始化分为3步:
- Resource定位,这步是Spring IoC容器根据开发者的配置,进行资源定位,在Spring开发中,通过XML或者注释都是很常见的方式,定位内容由开发者提供
- BeanDefinition的载入,这个过程就是Spring根据开发者的配置获取对应POJO,用以生成对应实例的过程
- BeanDefinition的注册,相当于把上一步中载入的POJO往Spring IoC容器中注册,这样就可以通过描述从中得到Spring IoC容器的Bean了
经过以上步骤,Bean就在IoC容器中得到了初始化,但是没有依赖注入,也就是没有注入其配置资源给Bean。
对于依赖注入,Spring Bean还有一个配置选项一一lazy-init,其含义就是是否初始化Spring Bean。在没有任何配置的情况下,它的默认值为default,实际值为false,也就是Spring IoC默认会自动初始化 Bean。如果将其设置为true,那么只有当我们使用Spring IoC容器的getBean方法获取它时,它才会进行初始化,完成依赖注入。
Spring Bean的生命周期
对于Bean而,在容器中存在其生命周期,它的初始化和销毁也需要一个过程,在 一些需要自定义的过程中,我们可以插入代码去改变它们的一些行为,以满足特定的需求。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vVx0cVgZ-1590394435475)(https://note.youdao.com/yws/res/15084/WEBRESOURCE64ad339ff72783037f95e2443c6ac5aa)]
注意以上的接口是针对什么而言的,大部分是针对单个Bean而言的:BeanPostProcessor接口则是针对所有Bean而言的,接口DisposableBean则是针对Spring IoC容器本身
下面有一个例子,展示出了Spring Beans的生命周期,这个例子是以果味饮料店相关的,我们可以提供给饮品店想要的口味等情况,然后饮品店会给我们产生饮料。
定义了我们想要的饮料“参数”
public class Source {
private String fruit;
private String sugar;
private String size;
/** getter and setter **/
}
定义了饮品店,并且实现了相应的接口,重写了方法:
public class JuiceMaker implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean {
private String juiceShop = null;
private Source source = null;
public String makeJuice() {
String juice = "这是一杯由" + juiceShop + "饮品店提供的" + source.getSize() + source.getSugar() + source.getFruit();
return juice;
}
// 自定义初始化方法
public void init() {
System.out.println("***"+this.getClass().getSimpleName()+"*** 执行自定义初始化方法");
}
// 自定义销毁方法
public void destory() {
System.out.println("***"+this.getClass().getSimpleName()+"*** 执行自定义销毁方法");
}
public void afterPropertiesSet() throws Exception {
System.out.println("***"+this.getClass().getSimpleName()+"*** 调用InitializingBean接口的afterPropertiesSet方法");
}
public void setApplicationContext(ApplicationContext arg0) throws BeansException {
System.out.println("***"+this.getClass().getSimpleName()+"*** 调用ApplicationContextAware接口的setApplicationContext方法");
}
public void setBeanFactory(BeanFactory arg0) throws BeansException {
System.out.println("***"+this.getClass().getSimpleName()+"*** 调用BeanFactoryAware接口的setBeanFactory方法");
}
public void setBeanName(String arg0) {
System.out.println("***"+this.getClass().getSimpleName()+"*** 调用BeanNameAware接口的setBeanName方法");
}
/** getter and setter **/
}
BeanPostProcessor接口的实现类,针对所有Bean
public class BeanPostProcessorImpl implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) {
System.out.println("---" + bean.getClass().getSimpleName() + "--- 对象" + beanName + "开始实例化");
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("---" + bean.getClass().getSimpleName() + "--- 对象" + beanName + "实例化完成");
return bean;
}
}
DisposableBean接口实现类,针对Spring IoC容器的销毁
public class DisposableBeanImpl implements DisposableBean {
public void destroy() throws Exception {
System.out.println("调用接口DisposableBean的destroy方法");
}
}
spring配置文件,里面定义了bean以及它们之间的依赖关系。在执行初始化时,是按照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.xsd">
<bean id="beanPostProcessor" class="bean.BeanPostProcessorImpl" />
<bean id="disposableBean" class="bean.DisposableBeanImpl" />
<bean id="source" class="pojo.Source">
<property name="fruit" value="橙汁" />
<property name="sugar" value="少糖" />
<property name="size" value="大杯" />
</bean>
<bean id="juiceMaker" class="pojo.JuiceMaker" init-method="init" destroy-method="destory">
<property name="juiceShop">
<value>七粒冰</value>
</property>
<property name="source" ref="source" />
</bean>
</beans>
下面是我们的测试类
public class Test {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
JuiceMaker juiceMaker = (JuiceMaker) context.getBean("juiceMaker");
System.out.println(juiceMaker.makeJuice());
context.close();
}
}
输出结果如下:
---DisposableBeanImpl--- 对象disposableBean开始实例化
---DisposableBeanImpl--- 对象disposableBean实例化完成
---Source--- 对象source开始实例化
---Source--- 对象source实例化完成
***JuiceMaker*** 调用BeanNameAware接口的setBeanName方法
***JuiceMaker*** 调用BeanFactoryAware接口的setBeanFactory方法
***JuiceMaker*** 调用ApplicationContextAware接口的setApplicationContext方法
---JuiceMaker--- 对象juiceMaker开始实例化
***JuiceMaker*** 调用InitializingBean接口的afterPropertiesSet方法
***JuiceMaker*** 执行自定义初始化方法
---JuiceMaker--- 对象juiceMaker实例化完成
这是一杯由七粒冰饮品店提供的大杯少糖橙汁
***JuiceMaker*** 执行自定义销毁方法
调用接口DisposableBean的destroy方法