IOC(inverse of control,控制-反转)
一、ioc概述
1.ioc的类型
ioc主要可以划分成三种类型:构造函数注入、属性注入和接口注入
2.通过容器完成依赖关系注入:
通过xml的方式配置Bean,在容器启动时,spring根据xml配置文件的
描述信息自动实例化Bean并完成依赖关系的装配,
这种实例化并注入依赖的能力是通过java的反射来实现的
二、相关java基础知识
java语言允许通过程序化的方式间接对Class进行操作。
Class文件有类装载器装载后, 在JVM中将形成一份描述Class结构的元信息对象,
通过该元信息对象可以获知Class的结构信息,如构造函数、属性和方法等。
Java允许用户借由这个与Class相关的元信息对象间接调用Class对象的功能,
这就为使用程序化方式操作Class对象开辟了途径
1、类装载器就ClassLoader
类装载器就是寻找类的字节码文件并构造出类在JVM内部表示对象的组件
类装载器把一个类装入JVM中,需要经过一下步骤:
(1)装载:查找和导入Class文件
(2)链接:执行校验、准备和解析步骤,其中解析步骤是可以选择的。
①校验:检查载入Class文件数据的正确性
②准备:给类的静态变量分配存储空间
③解析:将符号引用转换为直接引用
(3)初始化:对类的静态变量、静态代码块执行初始化工作
JVM装载类的时使用“全盘负责委托机制”
“全盘负责”:是指当一个ClassLoader装载一个类时,除非显式地使用另一个“ClassLoader”,
该类所依赖及引用的类也有这个ClassLoader载入;
“委托机制”:是指先委托父装载器寻找目标类,只有在找不到的情况下才从自己的类路径中查找
并装载目标类;
正因为有了“全盘负责委托机制”,java.lang.String 永远是由根装载器来装载的,
避免有人编写一个恶意的基础类(例如String)装载到JVM中
2.java反射机制
Class反射对象描述类的语义结构,
从Class对象可以获取构造函数、成员变量、方法类等类元素的反射对象
主要的反射类有三个:Controller、Method、Field 其他还有package、AnnotatedElement反射类
在访问private或protected成员变量或方法时,必须通过setAccessible(boolean access)方法取消
java语言检查,否则将抛出IllegalAccessException
三、资源访问利器 Resource
1、资源抽象接口
spring Resource接口为应用提供了更强的底层资源访问能力。该接口拥有对应不同资源类型的实现类
主要方法:
> boolean exists(): 资源是否存在
> boolean isOpen(): 资源是否打开
> URL getUTL() throws IOException: 如果底层资源可以表示成URL,则该方法返回对应不同类型的实现类
> File getFile() throws IOException: 如果底层资源对应一个文件,则该方法返回对应的File对象
> InputStream getInputStream() throws IOException: 返回资源对应的输入流
> WritableResource: 可写资源接口 实现类有FileSystemResource和PathResource
> ByteArrayResource: 二进制数组表示的资源
> ClassPathResource: 类路径下的资源
> FileSystemResource: 文件系统资源
> InputStreamResource: 以输入流返回表示的资源
> ServletContextResource: 为访问Web容器上下文中的资源而设计的类
> UrlResource: 使用户能够访问任何可以通过URL表示的资源
> PathResource: spring4.0提供读取资源文件的一个通用类
2、资源加载
spring能通过不同的资源地址前缀识别不同的资源类型。支持Ant风格通配符资源地址:? * **
资源地址前缀有:classpath:、file:、http://、ftp://等。
或者是没有前缀,根据ApplicationContext的具体实现类采用对应类型的Resource
在发布时如果资源配置文件被打包到jar包中。recource.getFile就无法读取了,
从而造成部署实施时出现意想不到的问题。因此我们建议尽量以流的方式读取
避免环境不同造成问题
四、BeanFactory和ApplicationContext
spirng通过配置文件描述Bean与Bean之间的依赖关系,利用Java语言的反射功能实例化Bean并建立Bean之间的依赖关系。
springIOC的容器在完成这些底层工作的基础上还提供了Bean实例缓存、生命周期管理、Bean实例代理、事件发布、资源装载等高级服务。
BeanFactory是spring框架最核心的接口,它提供了高级IOC的配置机制
BeanFactory是IOC容器,ApplicationContext为应用上下文,也称为Spring容器
BeanFactort是Spring框架的基础设施面向Spring本身;ApplicationContext面向使用Spring框架的开发者
1.BeanFactory在初始化容器时没有实例化Bean,直到第一次访问某个Bean时才实例化目标Bean
而ApplicationContext则在初始化应用上下文时就实例化所有单实例的Bean。
因此ApplicationContext的初始化时间会比BeanFactory稍长一些,不过稍后的调用则没有“第一次惩罚”的问题
2.通过HierarchicalBeanFactory接口,spring的IOC容器可以建立父子层级关联的容器体系
子容器可以访问父容器中的Bean,但父容器不能访问子容器中的Bean。
在容器内,Bean的Id必须是唯一的,但子容器可以拥有一个和父容器id相同的Bean。
五、Bean的生命周期
Bean生命周期多个特定的生命阶段组成,每个生命阶段都开出了一扇门,允许外界借由此门对Bean施加控制
spring中可以从两层面定义Bean的生命周期:
第一个层面是Bean的作用范围
第二个层面是实例化Bean时所经历的一系列阶段
1.BeanFactory中Bean的生命周期
1.当调用者通过getBean(beanName)向容器请求某一个Bean时,如果容器注册了
org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor接口
,实例化Bean之前,将调用接口的postProcessBeforeInstantiation方法。
2.根据配置情况调用Bean构造函数或工厂方法实例化Bean
3.如果容器注册了InstantiationAwarePostProcessor接口,那么在实例化Bean之后,
用该接口的postProcessAfterInstantiation()方法,可在这里对已经实例化的对象进行梳理打扮
4.如果Bean配置了属性信息,那么容器在这一步着手将配置值设置到Bean对应的属性中,不过在设置每个属性之前
将先调用InstantiationAwareBeanPostProcessor接口的postProcessValues()方法。
5.调用Bean的属性设置方法设置属性值
6.如果Bean实现了 org.springframework.beans.factory.BeanNameAWare 接口,则将调用setBeanName()接口方法,
将配置文件中该Bean对应的名称设置到Bean中
7.如果Bean实现了org.springframework.beans.factory.BeanFactoryAware接口,则将调用setBeanFactory()接口方法,
将BeanFactory容器实例设置到Bean中。
8.如果BeanFactory装配了org.springframework.beans.factory.config.BeanPostProcessor后处理器,
则将嗲用BeanPostProcessor的Object postProcessBeforeInitialzation(Object bean,String beanName)接口方法
对Bean进行加工操作。
其中入参bean是当前正在处理的Bean,而beanName是当前Bean的配置名,返回的对象为加工处理后的Bean
用户可以使用该方法对某些Bean进行特殊处理,甚至改变Bean的行为。
BeanPostProcessor在Spring框架中占有重要的地位,为容器提供对Bean后续加工处理的切入点
Spring提供的AOP、动态dialing等功能都通过BeanPostProcessor实施
9.如果Bean实现了InitialzaingBean接口,则将调用接口的afterPropertiseSet()方法
10.如果<bean>中通过init-method属性定义了初始化方法,则将执行这个方法。
11.BeanPostProcessor后处理器定义了两个方法:
其一是postProcessBeforeInitialization(),在第8步调用;
其二是Object postProcessAfterInitialization(Object bean,String beanName),这个方法在此时调用,
容器再次获得对Bean进行加工处理的机会
12.如果在<bean>中指定Bean的作用范围为scope = "prototype",则将Bean返回给调用者,调用者负责Bean后续的生命管理,
spring不再管理这个Bean的生命周期。如果将作用范围设置为scope="singleton",则将Bean放入SpringIoc容器的缓存池中,
并将Bean引用返回给调用者,Spring继续对这些Bean进行后续的生命管理。
13.对于scope="singleton"的Bean(默认情况),当容器关闭时,将触发Spring对Bean后续生命周期的管理工作。
如果Bean实现了DisposableBean接口,将调用接口destroy方法,可以在此编写释放资源,记录日志等操作。
14.对于scope="singleton"的Bean,如果通过<bean>的destroy-method属性指定了Bean的销毁方法,那么Spring将执行Bean等的这个方法,
完成Bean资源的释放等操作。
BeanFactory生命周期总结
Bean完整的生命周期中方法大致可以分为四类:
1.Bean自身的方法:
如调用Bean构造函数实例化Bean、调用Setter设置Bean的属性值及通过<bean>的init-method和destroy-method所指定的方法
2.Bean级生命周期接口方法:
如BeanNameAware、BeanFactoryAware、InitializatingBean和DisposableBean,这些接口方法有Bean类直接实现
3.容器级生命周期接口方法:
由InstantiationAwareBeanPostProcessor和BeanPostProcessor这两个接口实现的,一般称他们的实现类为“后处理器”。
后处理器接口一般不由Bean本身实现,他们独立于Bean,实现类以容器附加装置的形式注册到Spring容器中,并通过接口
反射为Spring容器扫描识别。当Spring容器创建任何Bean的时候,这些后处理器都会发生作用,所以这些处理器的影响是全局性的。
当然,用户可以通过合理地编写后处理器,让其仅对感兴趣的Bean进行加工处理
4.工厂后处理器接口方法:
包括AspectJWeavingEnable、CustomerAutowireConfigurer、ConfigurationClassPostProcessor等方法。
工厂后处理器也是容器级的,在应用上下文装配配置文件后立即调用
2.ApplicationContext中Bean的生命周期
1、Bean在应用上下文中的生命周期与在BeanFactory中类似,不同的是在第一步前如果配置了工厂后处理器接口BeanFactoryPostProcessor
的实现类,则在应用上下文加载配置后,初始化Bean实例之前将调用这些BeanFactoryPostProcessor对配置信息进行加工处理。
工厂后处理器是容器级的,仅在应用上下文初始化时调用一次,其目的是完成一些配置文件的加工处理工作
2.如果Bean实现了org.springframework.context.ApplicationContextAware接口,则会在第八步setBeanFactory后
调用setApplicationContext方法
3.ApplicationContext与BeanFactory的另一个最大不同是:
ApplicationContext会利用java反射机制自动识别出配置文件中定义的BeanPostProcessor、InstantiationAwareBeanPostProcessor
和BeanFactoryPostProcessor,并自动将它们注册到上下文中
BeanFactory则在代码中通过手工调用addBeanPostProcessor()方法进行注册
网友评论