【spring模拟】IOC描述及模拟

来源:互联网 发布:mac imovie 丢失 编辑:程序博客网 时间:2024/06/10 20:44

文章中的概念性知识引用自网络多篇文章,进行了简单的整理。

优秀文章:http://www.cnblogs.com/ITtangtang/p/3978349.html


Spring最重要的特性就是IOC(依赖注入)和AOP(切面编程)。


IOC:

IOC概念:

ioc用来控制对象声明周期(创建、销毁)和维护对象之间依赖关系。

IOC容器就是具有依赖注入功能的容器,IOC容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。应用程序无需直接在代码中new相关的对象,应用程序由IOC容器进行组装。在Spring中BeanFactory是IOC容器的实际代表者。

ioc通过读取配置文件中配置的元数据,通过元数据对应用中的各个对象进行实例化及装配。

Bean的概念:

由IOC容器管理的那些组成你应用程序的对象我们就叫它Bean, Bean就是由Spring容器初始化、装配及管理的对象。那IOC怎样确定如何实例化Bean、管理Bean之间的依赖关系以及管理Bean呢?这就需要配置元数据,在Spring中由BeanDefinition代表。

IOC优点:

非入侵:应用中的代码没有实现或者继承任何spring框架的类和接口。因而能非常容易替换spring。低耦合:客户端代码完全面向接口编程,无需知道实现类,可以通过修改配置文件来更换接口实现,客户端代码不需要任何修改。方便测试:如果在开发初期没有真正的实现,我们可以模拟一个实现来测试,不耦合代码。复用性好:Bean之间几乎没有依赖关系,容易复用。

IOC基本知识:

IOC注入时间:

用户第一次调用getBean,ioc容器触发依赖注入。用户为<bean>元素配置了lazy-init属性,触发依赖注入。

IOC注入方式:

1.xml注入2.set方法注入3.构造方法注入4.接口注入

IOC Bean作用域:

1.singleton:Bean以单实例的方式存在。2.prototype:一个bean可以定义多个实例。3.request:每次HTTP请求都会创建一个新的Bean。该作用域仅适用于WebApplicationContext环境。4.session:一个HTTP Session定义一个Bean。该作用域仅适用于WebApplicationContext环境.5.globalSession:同一个全局HTTP Session定义一个Bean。该作用域同样仅适用于WebApplicationContext环境.

IOC Bean生命周期:

1.实例化bean(前提是scope=singleton)实例化到内存。2.调用set方法设置属性。3.如果你实现了bean名字关注接口(BeanNameAware) 则,可以通过setBeanName获取id号。4. 如果你实现了 bean工厂关注接口,(BeanFactoryAware),则可以获取BeanFactory。5.如果你实现了 ApplicationContextAware接口,则调用方法。6.如果bean 和 一个后置处理器关联,则会自动去调用 Object postProcessBeforeInitialization方法。7.如果你实现InitializingBean 接口,则会调用 afterPropertiesSet。8.如果自己在<bean init-method=”init” /> 则可以在bean定义自己的初始化方法。9.如果bean 和 一个后置处理器关联,则会自动去调用 Object postProcessAfterInitialization方法。10.使用我们的bean。11. 容器关闭。12. 可以通过实现DisposableBean 接口来调用方法 destory。13. 可以在<bean destory-method=”method”/> 调用定制的销毁方法。

IOC自动装配类型:

1.no:默认的方式是不进行自动装配,通过手工设置ref 属性来进行装配bean。2.byName:通过参数名自动装配,Spring容器查找beans的属性,这些beans在XML配置文件中被设置为byName。之后容器试图匹配、装配和该bean的属性具有相同名字的bean.3.byType:通过参数的数据类型自动自动装配,Spring容器查找beans的属性,这些beans在XML配置文件中被设置为byType。之后容器试图匹配和装配和该bean的属性类型一样的bean。如果有多个bean符合条件,则抛出错误。4.constructor:这个同byType类似,不过是应用于构造函数的参数。如果在BeanFactory中不是恰好有一个bean与构造函数参数相同类型,则抛出一个严重的错误。5.autodetect:如果有默认的构造方法,通过 construct的方式自动装配,否则使用 byType的方式自动装配。

IOC Annotation注入:

@Resource:默认按名称装配,当找不到与名称匹配的bean时,才能按类型装配。@Autowired:默认按类型装配。

beanFactory和factoryBean:

BeanFactory:一种抽象工厂,Spring IoC容器的实际代表者。IoC容器负责容纳所有的bean,并对bean进行管理。Application,XmlBeanFactory等,这些都是IOC容器的具体表现。实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。FactoryBean:产生所需要的bean实例。

IOC容器初始化:

IoC容器的初始化就是对BeanDefinition的资源进行定位、载入、解析和注册这四个基本的过程。启动过程:(以FileSystemXmlApplicationContext为例)1. FileSystemXmlApplicationContext构造方法调用refresh()方法,这里是载入beanDefinition的入口2. refresh()方法在FileSystemXmlApplicationContext的父类AbstractApplicationContext中的实现,调用refreshBeanFactory()方法;3. refreshBeanFactory()方法在AbstractApplicationContext的子类AbstractRefreshableApplicationContext中实现,调用了loadBeanDefinition()方法,启动对beanDefinition的载入;4. loadBeanDefinition()在AbstractXmlApplicationContext中实现,调用了XmlBeanDefinitionReader的loadBeanDefinitions()方法。5. XmlBeanDefinitionReader的loadBeanDefinitions()实现了对于承载beanDefnition定义的xml文件的读入,以I/O的方式。6. 读入后,对beanDefinition进行解析。Bean解析采用SAX工具,先按照XML文件格式解析,再按照spring bean也有的定义解析,在BeanDefinitionParserDelegate.parseBeanDefinitionElement()实现。7. 最后对beanDefinition信息进行注册。就是将每个beanDefinition以key  =beanName,value = beanDefinition放入一个hashMap中,在DefaultListenableFactoty.RegisterBeanDefinition()中实现。经过IoC容器的初始化后,IoC容器持有beanDefintion,为依赖注入bean即调用getBean()方法奠定了基础。

IOC模拟:

模拟思路:

1.首先创建xml文件。配置节点。

2.创建实体对象,定义变量name和clazz,用来存放xml中的id和class的值。

2.使用dom4j或者其他方式读取配置文件,放入List<对象>集合中。

3.利用反射机制读取list中的对象,创建类的实例放入map中(key为实例的name,value为实例的value实例化的类)。

4.对外getBean()方法获取map中的实例对象。

XML文件:

<beans><bean id="myImitateService" class="com.xy.imitate.serviceImpl.MyImitateServiceImpl"><resource name="name" value="xuyang"/></bean></beans>

创建实例对象:

package com.xy.imitate.ioc;public class BeanDefinition {private String name;private String clazz;private Resource resource;      //get、set方法省略public BeanDefinition(String name, String clazz) {this.name = name;this.clazz = clazz;} }

package com.xy.imitate.ioc;public class Resource {private String name;private String value;      //get、set方法省略public Resource(String name, String value) {super();this.name = name;this.value = value;}}

创建service以及实现类:

package com.xy.imitate.service;public interface MyImitateService {public void sayHi();}

package com.xy.imitate.serviceImpl;import com.xy.imitate.service.MyImitateService;public class MyImitateServiceImpl implements MyImitateService {private String name;      //一定要提供set,使用反射机制调用set方法设置值public void setName(String name) {this.name = name;}public void sayHi() {System.out.println("Hello World,Hello Java~!I'm created by "+this.name +"!");}}

创建applicationContext上下文对象:

package com.xy.imitate.ioc;import java.io.File;import java.lang.reflect.Method;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import org.dom4j.Document;import org.dom4j.DocumentException;import org.dom4j.Element;import org.dom4j.io.SAXReader;/** * IOC模拟 *  * @author javaw  * 1.读取配置文件,通过节点获取id和name放进domain中 * 2.利用java反射机制将class实例放入Map中  * 3.读取map获取bean的实例 */public class IocImitateApplicationContext {private static List<BeanDefinition> beans = new ArrayList<BeanDefinition>();private static Map<String, Object> maps = new HashMap<String, Object>();public IocImitateApplicationContext() {//读取xml文件this.readXml();//初始化map中的元素this.instanceBeans();}private void instanceBeans() {for(BeanDefinition beanDefinition:beans){try {if(beanDefinition.getName()!=null&&!"".equals(beanDefinition.getName())){//得到class文件Class clazz = (Class) Class.forName(beanDefinition.getClazz());//实例化对象Object obejct = clazz.newInstance();//判断要注入的是不是为空,不为空则调用set方法注入if(beanDefinition.getResource()!=null){String name = beanDefinition.getResource().getName();String value = beanDefinition.getResource().getValue();//拼接set方法String methodName = "set"+name.substring(0,1).toUpperCase()+name.substring(1,name.length());//利用java反射机制调用方法Method method = clazz.getMethod(methodName, String.class);method.invoke(obejct, value);}maps.put(beanDefinition.getName(),obejct);}} catch (Exception e) {e.printStackTrace();}}}private void readXml() {try {SAXReader reader = new SAXReader();Document document = reader.read(new File("src/com/xy/imitate/ioc/bean.xml"));Element root = document.getRootElement();//获取标签为bean的节点List<Element> nodes = root.elements("bean");for(Element e : nodes){String id = e.attributeValue("id");String clazz = e.attributeValue("class");BeanDefinition beanDefinition = new BeanDefinition(id,clazz);//获取标签为resource的节点List<Element> smallNodes = e.elements("resource");for(Element e1 : smallNodes){String name = e1.attributeValue("name");String value = e1.attributeValue("value");Resource resource = new Resource(name,value);beanDefinition.setResource(resource);}beans.add(beanDefinition);}} catch (DocumentException e) {e.printStackTrace();}}public static Object getBean(String name){return maps.get(name);}}

测试:

package com.xy.imitate.ioc;import com.xy.imitate.service.MyImitateService;public class IocTest {public static void main(String[] args) {IocImitateApplicationContext applicationContext = new IocImitateApplicationContext();MyImitateService myImitateService = (MyImitateService)applicationContext.getBean("myImitateService");myImitateService.sayHi();}}

打印出来的结果:

Hello World,Hello Java~!I'm created by xuyang!

这样就模拟了spring ioc。

0 0
原创粉丝点击