spring(四):IoC
IoC—Inversion of Control,即控制反转
IoC意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。
理解IoC的关键:“谁控制谁,控制什么,为何是反转,哪些方面反转了”:
●谁控制谁,控制什么:传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由IoC容器来控制对象的创建;
谁控制谁?IoC 容器控制对象;
控制什么?控制外部资源获取。
●为何是反转,哪些方面反转了:传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象;而IoC则是由容器来帮忙创建及注入依赖对象;
为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;
哪些方面反转了?依赖对象的获取被反转了。
IoC很好的体现了面向对象设计法则之一—— 好莱坞法则:“别找我们,我们找你”
DI—Dependency Injection,即“依赖注入”
是组件之间依赖关系由容器在运行期决定,即由容器动态的将某个依赖关系注入到组件之中。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,而不需要关心具体的资源来自何处,由谁实现。
理解DI的关键是:“谁依赖谁,为什么需要依赖,谁注入谁,注入了什么”:
●谁依赖于谁:应用程序依赖于IoC容器;Bean依赖IoC容器;依赖指的是Bean之间的依赖关系
●为什么需要依赖:应用程序需要IoC容器来提供对象需要的外部资源;Bean需要IoC容器来创建
●谁注入谁:IoC容器注入应用程序某个对象,应用程序依赖的对象;
●注入了什么:注入某个对象所需要的外部资源(包括对象、资源、常量数据)。
Spring IoC容器如何知道哪些是它管理的对象呢?
Spring IoC容器通过读取配置文件中的配置元数据(BeanDefinition),通过元数据对应用中的各个对象进行实例化及装配。
Spring与配置文件完全解耦,可以使用任何可能的方式进行配置元数据,比如注解、基于xml的、基于java文件的、基于属性文件的配置。
由IoC容器管理的那些组成应用程序的对象我们就叫它Bean。
在Spring中BeanFactory是IoC容器的实际代表者。ApplicationContext 接口继承了BeanFactory。简单说, BeanFactory提供了IoC容器最基本功能,而 ApplicationContext 则增加了更多支持企业级功能支持。
public static void main(String[] args) {
// 1、读取配置文件实例化一个IoC容器
ApplicationContext context = new ClassPathXmlApplicationContext("hello.xml");
// 2、从容器中获取Bean,注意此处完全“面向接口编程,而不是面向实现”
HelloApi helloApi = context.getBean("hello", HelloApi.class);
// 3、执行业务逻辑
helloApi.sayHello();
}
Bean?
本质就是一个POJO类,但具有以下限制:
- 该类必须要有公共的无参构造器
- 属性为private访问级别,不建议public,如private String message
- 属性必要时通过一组setter和getter方法来访问
作用域
Spring 框架支持以下五个作用域,分别为singleton、prototype、request、session和global session。
作用域 | 描述 |
---|---|
singleton | Spring会缓存单例对象,在IoC容器仅存在一个Bean实例,默认值 |
prototype | Spring不会缓存原型对象,每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行newXxxBean() |
request | 每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境 |
session | 同一个HTTP Session共享一个Bean,不同Session使用不同的Bean,仅适用于WebApplicationContext环境 |
global-session | 一般用于Portlet应用环境,该运用域仅适用于WebApplicationContext环境 |
<bean id="..." class="..." scope="singleton"></bean>
自定义作用域:org.springframework.beans.factory.config.Scope
生命周期
Bean的生命周期可以表达为:Bean的定义——Bean的初始化——Bean的使用——Bean的销毁
初始化回调
一、org.springframework.beans.factory.InitializingBean 接口指定一个单一的方法:
void afterPropertiesSet() throws Exception;
二、配置元数据,使用 init-method 属性来指定带有 void 无参数方法的名称:
<bean id="exampleBean" class="examples.ExampleBean" init-method="init"/>
销毁回调
一、org.springframework.beans.factory.DisposableBean 接口指定一个单一的方法:
void destroy() throws Exception;
二、配置元数据,你使用 destroy-method 属性来指定带有 void 无参数方法的名称:
<bean id="exampleBean" class="examples.ExampleBean" destroy-method="destroy"/>
后置处理器
允许在调用初始化方法前后对 Bean 进行额外的处理。
是一个监听器,它可以监听容器触发的事件。将它向IoC容器注册后,容器中管理的Bean具备了接收IoC容器事件回调的能力。
在populateBean之后的initializeBean中被调用。在Bean的初始化之前提供postProcessBeforeInitialization回调入口。在Bean的初始化之后提供postProcessAfterInitialization回调入口。
public class InitBean implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("BeforeInitialization : " + beanName);
return bean; // you can return any other object as well
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("AfterInitialization : " + beanName);
return bean; // you can return any other object as well
}
}
Bean自身的方法:如调用 Bean 构造函数实例化 Bean,调用 Setter 设置 Bean 的属性值以及通过的 init-method 和 destroy-method 所指定的方法;
Bean级生命周期接口方法:如 BeanNameAware、 BeanFactoryAware、 InitializingBean 和 DisposableBean,这些接口方法由 Bean 类直接实现;
容器级生命周期接口方法:在上图中带“★” 的步骤是由 InstantiationAwareBean PostProcessor 和 BeanPostProcessor 这两个接口实现,一般称它们的实现类为“ 后处理器” 。 后处理器接口一般不由 Bean 本身实现,它们独立于 Bean,实现类以容器附加装置的形式注册到 Spring 容器中并通过接口反射为 Spring 容器预先识别。当Spring 容器创建任何 Bean 的时候,这些后处理器都会发生作用,所以这些后处理器的影响是全局性的。当然,用户可以通过合理地编写后处理器,让其仅对感兴趣Bean 进行加工处理
Spring IoC容器如何实例化Bean呢?
IoC容器需要根据Bean定义里的配置元数据使用反射机制来创建Bean。
一、使用构造器实例化Bean
指定必须的class属性
<bean id="hello" class="hello.HelloApiImpl"></bean>
二、使用静态工厂方式实例化Bean
指定必须的class属性
指定factory-method属性来指定实例化Bean的方法
<bean id="hello" class="hello.HelloApiStaticFactory" factory-method="newInstance"></bean>
三、使用实例工厂方法实例化Bean
不能指定class属性
使用factory-bean属性指定工厂Bean
使用factory-method属性指定实例化Bean的方法
<!—定义实例工厂Bean -->
<bean id="beanInstanceFactory" class="hello.HelloApiInstanceFactory"/>
<!—使用实例工厂Bean创建Bean -->
<bean id="hello" factory-bean="beanInstanceFactory" factory-method="newInstance"></bean>
Spring IoC容器如何注入Bean的依赖资源?
在基于构造函数注入中,我们使用的是〈bean〉标签中的〈constructor-arg〉元素;
而在基于设值函数的注入中,我们使用的是〈bean〉标签中的〈property〉元素。
构造器注入:
实例化Bean时,通过在Bean定义中指定构造器参数进行注入依赖,包括实例工厂方法参数注入依赖,但静态工厂方法参数不允许注入依赖;
- 根据参数索引注入
<constructor-arg index="0" value="Hello World!"/>
构造函数的参数在 bean 定义中的顺序就是把这些参数提供给适当的构造函数的顺序。
最好的传递构造函数参数的方式,是使用 index 属性来显式的指定构造函数参数的索引。
- 根据参数类型注入
<constructor-arg type="java.lang.String" value="Hello World!"/>
- 根据参数名注入:在构造器上使用@ConstructorProperties注解来指定参数名。只对构造器实例化Bean方式起作用,而对工厂不起作用。
<constructor-arg name="message" value="Hello World!"/>
setter注入:
实例化Bean后,通过调用Bean类的setter方法进行注入依赖;
- 注入常量:
<property name="message" value="Hello World!"/>
<property name="message"><value>Hello World!</value></property>
- 注入Bean ID:
<property name="id"><idref bean="bean1"/></property>
- 注入集合(Collection、Set、List):
<property name="values">
<list value-type="可选" merge="可选">
<value>1</value>
<value>2</value>
<value>3</value>
</list>
</property>
<property name="values"><set value-type="同上">...</set></property>
- 注入数组:
一维:
<property name="id">
<array>...</array>
</property>
二维:
<property name="id">
<array>
<array>...</array>
<array>...</array>
</array>
</property>
- 注入字典:
<property name="id">
<map>
<entry key="" value=""/>
<entry key="" value=""/>
</map>
</property>
- 注入Properties:
<property name="id">
<props value-type="无用,就是String">
<prop key="">value</prop>
<prop key="">value</prop>
</map>
</property>
- 注入依赖Bean:
如果你想要向一个对象传递一个引用,你需要使用标签的 ref 属性,如果你想要直接传递值,那么你应该使用如上所示的 value 属性。
一般:
<constructor-arg index="0" ref="bean1"/>
<property name="helloApi" ref="bean1"/>
高级:
<ref local=""/>
<ref parent=""/>
<!-- sources/chapter3/parentBeanInject.xml表示父容器配置-->
<!--注意此处可能子容器也定义一个该Bean-->
<bean id="helloApi" class="cn.HelloImpl4">
<property name="message" value="Hello Parent!"/>
</bean>
<!-- sources/chapter3/localBeanInject.xml表示当前容器配置-->
<!-- 注意父容器中也定义了id 为 helloApi的Bean -->
<bean id="helloApi" class="cn.HelloImpl4">
<property name="message" value="Hello Local!"/>
</bean>
<!-- 通过local注入 -->
<bean id="bean1" class="cn.bean.HelloApiDecorator">
<constructor-arg index="0"><ref local="helloApi"/></constructor-arg>
</bean>
<!-- 通过parent注入 -->
<bean id="bean2" class="cn.bean.HelloApiDecorator">
<property name="helloApi"><ref parent="helloApi"/></property>
</bean>
- 注入内部Bean:
<bean id="bean" class="cn.bean.HelloApiDecorator">
<property name="helloApi">
<bean id="即便指定也没有用,是匿名的,对外部不可见" class="cn.hello.HelloImpl"/>
</property>
</bean>
- 处理null值:
<property name=""><null/></property>
Spring Bean自动装配?(不建议用
在 XML 配置文件中 beans 的 auto-wire 属性设置为 byName。然后,它尝试将它的属性与配置文件中定义为相同名称的 beans 进行匹配和连接。
在 XML 配置文件中 beans 的 autowire 属性设置为 byType。然后,如果它的 type 恰好与配置文件中 beans 名称中的一个相匹配,它将尝试匹配和连接它的属性。
在 XML 配置文件中 beans 的 autowire 属性设置为 constructor。然后,它尝试把它的构造函数的参数与配置文件中 beans 名称中的一个进行匹配和连线。
spring(四):IoC的更多相关文章
- Spring框架系列(四)--IOC控制反转和DI依赖注入
背景: 如果对象的引用或者依赖关系的管理由具体对象完成,代码的耦合性就会很高,代码测试也变得困难.而IOC可以很好的解决这个问题,把这 些依赖关系交给框架或者IOC容器进行管理,简化了开发. IOC是 ...
- spring四种依赖注入方式
一.Set注入 这是最简单的注入方式,假设有一个SpringAction,类中需要实例化一个SpringDao对象,那么就可以定义一个private的SpringDao成员变量,然后创建SpringD ...
- Spring总结—— IOC 和 Bean 的总结
一.Spring 官方文档中给出的 Spring 的整体结构. 二.我自己所理解的 Spring 整体结构图. 三.本次总结 Spring 核心部分 1.从上面图中可以看出,Beans 和 Conte ...
- spring容器IOC创建对象<二>
问题?spring是如何创建对象的?什么时候创建对象?有几种创建方式?测试对象是单例的还是多例的 ?对象的初始化和销毁? 下面的四大模块IOC的内容了!需要深刻理解 SpringIOC定义:把对象的创 ...
- Spring的IoC应用
IoC(Inversion of Control,控制反转) Spring的IoC应用是其框架的最大的特点,通过依赖注入可以大大降低代码之间的耦合度,从而实现代码和功能之间的分离.在代码中可以不直接和 ...
- Spring的IOC
引用:http://www.cnblogs.com/xdp-gacl/p/4249939.html 学习过Spring框架的人一定都会听过Spring的IoC(控制反转) .DI(依赖注入)这两个概念 ...
- Spring的IOC原理[通俗解释一下]
Spring的IOC原理[通俗解释一下] 1. IoC理论的背景我们都知道,在采用面向对象方法设计的软件系统中,它的底层实现都是由N个对象组成的,所有的对象通过彼此的合作,最终实现系统的业务逻辑. 图 ...
- Spring的IOC容器第一辑
一.Spring的IOC容器概述 Spring的IOC的过程也被称为依赖注入(DI),那么对象可以通过构造函数参数,工厂方法的参数或在工厂方法构造或返回的对象实例上设置的属性来定义它们的依赖关系,然后 ...
- (转)java之Spring(IOC)注解装配Bean详解
java之Spring(IOC)注解装配Bean详解 在这里我们要详细说明一下利用Annotation-注解来装配Bean. 因为如果你学会了注解,你就再也不愿意去手动配置xml文件了,下面就看看 ...
- 【死磕 Spring】----- IOC 之解析 bean 标签:开启解析进程
原文出自:http://cmsblogs.com import 标签解析完毕了,再看 Spring 中最复杂也是最重要的标签 bean 标签的解析过程. 在方法 parseDefaultElement ...
随机推荐
- Arduino上搭建ESP8266环境
我尝试了各种方法都无法在Arduino上安装ESP8266的环境,最后发现离线安装最稳妥. 1. 下载安装包,提取码:pktw 2. 将安装包内所有文件拷贝到C:\Users\Administrato ...
- mui下拉上拉(明一)
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name ...
- 【已解决】redis-py-cluster安装成功但导入失败,提示cannot import name b
背景: 一直跑的好好的自动化突然跑不起来了,提示是在导包的时候发生错误 发生错误的行是 from rediscluster import StrictRedisCluster 提示信息如下 检查安装包 ...
- 885.求组合数 I(模板)
O(n^2) 数据范围 a*b =4e6 根据组合数公式: 代码: import java.util.Scanner; public class Main{ static final int N=2 ...
- 一道有趣的for循环题
一道有趣的for循环题 今天在复习js基础知识时发现了一个for循环的题,第一眼看到直接懵逼了,没想到for循环竟然还可以这样玩?涨姿势了. 题目是这样的 for(i=0, j=0; i<10, ...
- springboot的yml配置文件里有多个参数的调用方式
本篇教程适用于配置文件一级下有多个二级或三级时,如何在service层不用通过多个@Value就能获取配置文件的参数 例如yml配置是这样的: 如果service层要引用这些参数,用多个@Value( ...
- 【android】Parcelable的相关技术总结
关于Parcelable的相关知识学习 进行Android开发的时候,无法将对象的引用传给Activities或者Fragments,我们需要将这些对象放到一个Intent或者Bundle里面,然 ...
- 关于docker容器访问的主机的端口问题
docker容器需要访问主机的,不能使用127.0.0.1,127.0.0.1访问的是docker容器不是主机: docker容器创建时会分配一个主机ip,可在主机使用命令 docker inspec ...
- Hdu2099 整除的尾数
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2099 Problem Description 一个整数,只知道前几位,不知道末二位,被另一个整数除尽了 ...
- java8的ConcurrentHashMap为何放弃分段锁,为什么要使用CAS+Synchronized取代Segment+ReentrantLock
原文地址:https://cloud.tencent.com/developer/article/1509556 推荐一篇 ConcurrentHashMap 和 HashMap 写的比较的的文章 j ...