Spring之IOC实现原理
2015-04-20 16:28
323 查看
前段时间写了篇关于Spring的AOP框架实现原理的文章,现在浅谈下Spring的另一大核心概念IOC的原理。
IOC:即控制反转。官方解释是让调用类对某一接口实现类的依赖关系由第三方注入,以转移调用类对某一接口实现类的依赖。
下面将举个现实例子加深理解:
“剧本”要选定“角色”的“饰演者”,我们可以创建第三方“导演“来控制”剧本”,引入“导演”,“剧本”和“饰演者”将完全解偶。”导演“将拥有对”饰演者“的控制权,反转权则是指由”剧本“转移到了导演身上。
我们重新来看IOC的定义:
IOC:即控制反转。官方解释是让调用类(”剧本“)对某一接口实现类(”饰演者“)的依赖关系由第三方(”导演“)注入,以转移调用类(”剧本“)对某一接口实现类(”饰演者“)的依赖。
从注入方法上看,划分为三种类型
1.构造方法注入
2.属性注入
3.接口注入
下面我们通过(剧本-饰演者问题)来看注入的具体方式
构造方法注入:通过调用类的构造方法,将接口实现类通过构造方法变量传入
调用类(剧本)
第三方类(导演)
属性注入:通过Setter方法完成调用类所需依赖的注入,更加灵活方便
调用类(剧本)
第三方类(导演)
接口注入:将调用类所有依赖注入的方法抽取到一个接口中,调用类通过实现该接口提供相应的注入方法。
1.调用类所依赖的注入方法提取到接口中
2.调用类实现接口
Spring作为一个容器,通过配置文件或者注解描述类和类之间的依赖关系,自动完成类的初始化和依赖注入的工作,下面是对以上实例进行配置的配置文件片段:
前面写过关于Java反射机制的文章,那么Java反射与IOC的关系是…?
在Spring中,通过IOC可以将实现类、参数信息等配置在其对应的配置文件中,那么当需要更改实现类或参数信息时,只需要修改配置文件即可, 我们还可以对某对象所需要的其它对象进行注入,这种注入都是在配置文件中做的。
Spring的IOC的实现原理利用的就是Java的反射机制,Spring的工厂类会帮我们完成配置文件的读取、利用反射机制注入对象等工作,我们可以通过bean的名称获取对应的对象。
下面我简单实现IOC如何利用反射从配置文件中读取信息
1.需要从配置文件(xml)中读取配置信息
2.配置文件
3.对应的JavaBean
资源访问工具类
JDK所提供的访问资源的类并不能很好的满足各种底层资源的访问需求,因此,Spring设计了一个Resource接口,它为应用提供了更强大的访问底层资源的能力
主要方法:
1. boolean exists()
2. boolean isOpen()
3. URL getURL()
4. File getFile()
5. InputStream getInputStream()
具体实现类:
1. ByteArrayResource
2. ClassPathResource
3. FileSystemResource
4. InputStreamResource
5. ServletContextResource
6. UrlResource
为了访问不同类型的资源,必须使用相应的Resource实现类,这是比较麻烦的,Spring提供了一个强大的加载资源的机制,能够自动识别不同的资源类型:
资源类型地址前缀:
1. classpath classpath:com/xxx/bean.xml
2. File file:/com/xxx/bean.xml
3. http:// http://www.xxx.com/bean.xml
4. ftp ftp://www.xxx.com/bean.xml
5. 无前缀 com/jike/bean.xml
Ant风格的匹配符:
1. ?:匹配文件名中的一个字符
2. *:匹配文件名中的任意字符
3. **:匹配多层路径
Ant风格的资源路径示例:
1. Classpath:com/t*st.xml
2. File:D:/conf/*.xml
3. Classpath:com/**/test.xml
4. Classpath:org/springframework/*/.xml
Spring定义了一套资源加载的接口,并提供了实现类,如下:
BeanFactory和ApplicationContext
BeanFactory是Spring框架最核心的接口,它提供了高级IoC的配置机制。ApplicationContext建立在BeanFactory基础之上,提供了更多面向应用的功能,它提供了国际化支持和框架事件体系,更易于创建实际应用一般成BeanFactory为IoC容器,而称ApplicationContext为应用上下文
BeanFactory
BeanFactory是一个类工厂,可以创建并管理各种类的对象,Spring称这些创建和管理的Java对象为Bean。在Spring中,Java对象的范围更加宽泛。接下来我们对BeanFactory的类体系结构以及装载初始化顺序进行说明:
类体系结构:
1. XmlBeanFactory
2. ListableBeanFactory
3. HierarhicalBeanFactory
4. ConfigurableBeanFactory
5. AutowireCapableBeanFactory
6. SingletonBeanFactory
7. BeanDefinitionRegistry
初始化顺序:
1. 创建配置文件
2. 装载配置文件
3. 启动IoC容器
4. 获取Bean实例
ApplicationContext
ApplicationContext由BeanFactory派生而来,提供了更多面向实际应用的功能。在BeanFactory中,很多功能需要以编程的方式方式实现,而在ApplicationContext中则可以通过配置的方式实现。
具体实现类:
1.ClassPathXmlApplicationContext
2.FileSystemXmlApplicationContext
3.ConfigurableApplicationContext
扩展接口:
1.ApplicationEventPublisher
2.MessageSource
3.ReaourcePatternResolver
4.LifeCycle
和BeanFactory初始化相似,ApplicationContext的初始化也很简单,根据配置文件路径不同可以选择不同的实现类加载:
ClassPathXmlApplicationContext
FileSystemXmlApplicationContext
Bean的实例化问题
使用BeanFactory从xml配置文件加载bean:
使用ApplicationConText从xml配置文件加载bean:
BeanFactory在初始化容器时并没有实例化Bean,直到第一次访问Bean时才实例化具体的Bean。
ApplicationContext则在初始化上下文时则实例单实例的Bean
IOC:即控制反转。官方解释是让调用类对某一接口实现类的依赖关系由第三方注入,以转移调用类对某一接口实现类的依赖。
下面将举个现实例子加深理解:
“剧本”要选定“角色”的“饰演者”,我们可以创建第三方“导演“来控制”剧本”,引入“导演”,“剧本”和“饰演者”将完全解偶。”导演“将拥有对”饰演者“的控制权,反转权则是指由”剧本“转移到了导演身上。
我们重新来看IOC的定义:
IOC:即控制反转。官方解释是让调用类(”剧本“)对某一接口实现类(”饰演者“)的依赖关系由第三方(”导演“)注入,以转移调用类(”剧本“)对某一接口实现类(”饰演者“)的依赖。
从注入方法上看,划分为三种类型
1.构造方法注入
2.属性注入
3.接口注入
下面我们通过(剧本-饰演者问题)来看注入的具体方式
构造方法注入:通过调用类的构造方法,将接口实现类通过构造方法变量传入
调用类(剧本)
Public class JuBen { private JueSe Js; //1:注入角色的具体扮演者 public JuBen(JueSe Js) { this.Js=Js; } public void DuiBai() { Js.declare(“我想做一个好人!”); }
第三方类(导演)
Public class Director { public void direct() { //2.指定角色的扮演者 JueSe Js = new LiuDeHua(); //3.注入具体扮演者到剧本中 JuBen Jb = new JuBen(Js); Jb.DuiBai(); } }
属性注入:通过Setter方法完成调用类所需依赖的注入,更加灵活方便
调用类(剧本)
Public class JuBen { private JueSe Js; //1.属性注入方法 public void setJueSe(JueSe Js) { this.Js=Js; } public void DuiBai(){ Js.declare(“我想做一个好人!”); } }
第三方类(导演)
Public class Director { public void direct() { JueSe Js=new LiuDeHua(); JuBen Jb=new JuBen(); //2.调用属性Setter方法注入 Jb.setJueSe(Js); Jb.DuiBai(); }
接口注入:将调用类所有依赖注入的方法抽取到一个接口中,调用类通过实现该接口提供相应的注入方法。
1.调用类所依赖的注入方法提取到接口中
Public interface ActorArrangable { void injectJs(JueSe Js); }
2.调用类实现接口
Public class JuBen implements ActorArrangable { private JueSe Js; //1.实现接口方法 public void injectJs(JueSe Js) {this.Js = Js; } public void DuiBai() { Js.declare(“我想做一个好人!”) } }
Spring作为一个容器,通过配置文件或者注解描述类和类之间的依赖关系,自动完成类的初始化和依赖注入的工作,下面是对以上实例进行配置的配置文件片段:
//1.实现类实例化 <bean id=“Js" class=“LiuDeHua" /> //2.通过ljm-ref建立依赖关系 <bean id=“Juben" class=“JuBen" p:ljm-ref=“Js”/> </beans>
前面写过关于Java反射机制的文章,那么Java反射与IOC的关系是…?
在Spring中,通过IOC可以将实现类、参数信息等配置在其对应的配置文件中,那么当需要更改实现类或参数信息时,只需要修改配置文件即可, 我们还可以对某对象所需要的其它对象进行注入,这种注入都是在配置文件中做的。
Spring的IOC的实现原理利用的就是Java的反射机制,Spring的工厂类会帮我们完成配置文件的读取、利用反射机制注入对象等工作,我们可以通过bean的名称获取对应的对象。
下面我简单实现IOC如何利用反射从配置文件中读取信息
1.需要从配置文件(xml)中读取配置信息
package com.reflect; import java.io.InputStream; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.dom4j.Attribute; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.io.SAXReader; public class BeanFactory { private Map<String, Object> beanMap = new HashMap<String, Object>(); /** * bean工厂的初始化. * * @param xml xml配置文件 */ public void init(String xml) { try { //1.创建读取配置文件的reader对象 SAXReader reader = new SAXReader(); //2.获取当前线程中的类装载器对象 ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); //3.从class目录下获取指定的xml文件 InputStream ins = classLoader.getResourceAsStream(xml); Document doc = reader.read(ins); Element root = doc.getRootElement(); Element foo; //4.遍历xml文件当中的Bean实例 for (Iterator i = root.elementIterator("bean"); i.hasNext();) { foo = (Element) i.next(); //5.针对每个一个Bean实例,获取bean的属性id和class Attribute id = foo.attribute("id"); Attribute cls = foo.attribute("class"); //6.利用Java反射机制,通过class的名称获取Class对象 Class bean = Class.forName(cls.getText()); //7.获取对应class的信息 java.beans.BeanInfo info = java.beans.Introspector.getBeanInfo(bean); //8.获取其属性描述 java.beans.PropertyDescriptor pd[] = info.getPropertyDescriptors(); //9.创建一个对象,并在接下来的代码中为对象的属性赋值 Object obj = bean.newInstance(); //10.遍历该bean的property属性 for (Iterator ite = foo.elementIterator("property"); ite.hasNext();) { Element foo2 = (Element) ite.next(); //11.获取该property的name属性 Attribute name = foo2.attribute("name"); String value = null; //12.获取该property的子元素value的值 for (Iterator ite1 = foo2.elementIterator("value"); ite1.hasNext();) { Element node = (Element) ite1.next(); value = node.getText(); break; } //13.利用Java的反射机制调用对象的某个set方法,并将值设置进去 for (int k = 0; k < pd.length; k++) { if (pd[k].getName().equalsIgnoreCase(name.getText())) { Method mSet = null; mSet = pd[k].getWriteMethod(); mSet.invoke(obj, value); } } } //14.将对象放入beanMap中,其中key为id值,value为对象 beanMap.put(id.getText(), obj); } } catch (Exception e) { System.out.println(e.toString()); } } /** * 通过bean的id获取bean的对象. * * @param beanName * bean的id * @return 返回对应对象 */ public Object getBean(String beanName) { Object obj = beanMap.get(beanName); return obj; } /** * 测试方法. * * @param args */ public static void main(String[] args) { BeanFactory factory = new BeanFactory(); factory.init("conf/config.xml"); JavaBean javaBean = (JavaBean) factory.getBean("javaBean"); System.out.println("userName=" + javaBean.getUserName()); System.out.println("password=" + javaBean.getPassword()); } }
2.配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans> <bean id="javaBean" class="com.jike.spring.chapter03.reflect.JavaBean"> <property name="userName"> <value>Jonney</value> </property> <property name="password"> <value>1234567890</value> </property> </bean> </beans>
3.对应的JavaBean
package com.reflect; public class JavaBean { private String userName; private String password; public String getPassword() { return password; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public void setPassword(String password) { this.password = password; } }
资源访问工具类
JDK所提供的访问资源的类并不能很好的满足各种底层资源的访问需求,因此,Spring设计了一个Resource接口,它为应用提供了更强大的访问底层资源的能力
主要方法:
1. boolean exists()
2. boolean isOpen()
3. URL getURL()
4. File getFile()
5. InputStream getInputStream()
具体实现类:
1. ByteArrayResource
2. ClassPathResource
3. FileSystemResource
4. InputStreamResource
5. ServletContextResource
6. UrlResource
为了访问不同类型的资源,必须使用相应的Resource实现类,这是比较麻烦的,Spring提供了一个强大的加载资源的机制,能够自动识别不同的资源类型:
资源类型地址前缀:
1. classpath classpath:com/xxx/bean.xml
2. File file:/com/xxx/bean.xml
3. http:// http://www.xxx.com/bean.xml
4. ftp ftp://www.xxx.com/bean.xml
5. 无前缀 com/jike/bean.xml
Ant风格的匹配符:
1. ?:匹配文件名中的一个字符
2. *:匹配文件名中的任意字符
3. **:匹配多层路径
Ant风格的资源路径示例:
1. Classpath:com/t*st.xml
2. File:D:/conf/*.xml
3. Classpath:com/**/test.xml
4. Classpath:org/springframework/*/.xml
Spring定义了一套资源加载的接口,并提供了实现类,如下:
BeanFactory和ApplicationContext
BeanFactory是Spring框架最核心的接口,它提供了高级IoC的配置机制。ApplicationContext建立在BeanFactory基础之上,提供了更多面向应用的功能,它提供了国际化支持和框架事件体系,更易于创建实际应用一般成BeanFactory为IoC容器,而称ApplicationContext为应用上下文
BeanFactory
BeanFactory是一个类工厂,可以创建并管理各种类的对象,Spring称这些创建和管理的Java对象为Bean。在Spring中,Java对象的范围更加宽泛。接下来我们对BeanFactory的类体系结构以及装载初始化顺序进行说明:
类体系结构:
1. XmlBeanFactory
2. ListableBeanFactory
3. HierarhicalBeanFactory
4. ConfigurableBeanFactory
5. AutowireCapableBeanFactory
6. SingletonBeanFactory
7. BeanDefinitionRegistry
初始化顺序:
1. 创建配置文件
2. 装载配置文件
3. 启动IoC容器
4. 获取Bean实例
ApplicationContext
ApplicationContext由BeanFactory派生而来,提供了更多面向实际应用的功能。在BeanFactory中,很多功能需要以编程的方式方式实现,而在ApplicationContext中则可以通过配置的方式实现。
具体实现类:
1.ClassPathXmlApplicationContext
2.FileSystemXmlApplicationContext
3.ConfigurableApplicationContext
扩展接口:
1.ApplicationEventPublisher
2.MessageSource
3.ReaourcePatternResolver
4.LifeCycle
和BeanFactory初始化相似,ApplicationContext的初始化也很简单,根据配置文件路径不同可以选择不同的实现类加载:
ClassPathXmlApplicationContext
FileSystemXmlApplicationContext
Bean的实例化问题
使用BeanFactory从xml配置文件加载bean:
import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.core.io.FileSystemResource; public class XmlConfigWithBeanFactory { public static void main(String[] args) { XmlBeanFactory factory = new XmlBeanFactory(newFileSystemResource( "build/beans.xml")); } }
使用ApplicationConText从xml配置文件加载bean:
public class XmlConfigWithApplication{ public static void main(String[] args){ ApplicationContext application = new ClassPathXmlApplicationContext(beans.xml")); application.getBean("BeanName"); } }
BeanFactory在初始化容器时并没有实例化Bean,直到第一次访问Bean时才实例化具体的Bean。
ApplicationContext则在初始化上下文时则实例单实例的Bean
相关文章推荐
- 反射 实现工厂模式 和 spring IOC 实现原理
- 番外 01:Spring IoC 实现原理简析,Java的反射机制,通过类名创建对象
- Spring技术内幕——深入解析Spring架构与设计原理(一)IOC实现原理
- [Spring] IOC的实现原理—反射与工厂模式
- Spring IOC、DI、AOP原理和实现
- spring源码学习之路---IOC实现原理(二)
- Spring学习06--IOC实现原理以及IOC容器初始化过程
- spring IOC 实现原理模拟实现
- 耦合实现Spring IOC原理解析
- Spring IOC/BeanFactory/ApplicationContext的工作流程/实现原理/初始化/依赖注入源码详解
- Spring技术内幕——深入解析Spring架构与设计原理(一)IOC实现原理
- spring源码学习之路---IOC实现原理
- Spring技术内幕——深入解析Spring架构与设计原理(一)IOC实现原理
- Spring学习笔记 IOC原理实现
- spring源码学习之路---IOC实现原理(三)
- Spring IOC、DI、AOP原理和实现
- Spring技术内幕——深入解析Spring架构与设计原理(一)IOC实现原理
- spring的IOC操作及实现原理
- Spring技术内幕——深入解析Spring架构与设计原理(一)IOC实现原理
- Spring技术内幕——深入解析Spring架构与设计原理(一)IOC实现原理