日期:2014-05-18  浏览次数:20645 次

一些关于Ioc的个人见解,希望网友来拍砖
一直想弄个Ioc工具,今天把自己的一些想法整理了一下,希望网友来拍砖!

1.1:容器初探
在Ioc应用中,容器扮演了非常重要的角色,它负管理对象定义维护,对象的创建,对象之间的关系等等,开发人员只需要调用容器的context即可获得所需要的对象实例,而不再需要在程序中通过New关键字去创建了,关于该技术的优点,在,网上一大堆,此就不再罗嗦了,
下面我们主要从技术层面谈谈容器的内部原理


1.2:理解注入
相信从事Java开发的人都知道,一个普通的Java Bean的组成结构:成员字段,Get/Set方法,构造方法和其他方法。在实际使用的过程中,往往需要调用Bean的Set方法或业务方法,将所需要的值传入对象的内部,从而达到影响对象的后续其他操作,在没有容器的情况下,我们往往需要调用对象的set方法去放值;但是有了容器之后,它则以代理的方式将所需的值放入对象内部,调用本质未变,只是调用者不同而已。业界将这个容器调用对象赋值的方式,取了一个很形象化的称谓:注入。

1.3:注入什么
上文谈到了 “注入” 一词,这个词从字眼来是个动词,如果补充完整,这句话可以表达为:容器将参数注入对象内部,这句话的着力点:参数。按照Java一切都是对象思想,参数也应是对象,在注入之前, Bean容器是需要准备好相应的参数对象,那么对于容器而言,是如何构造参数对象的呢?根据目前大多容器,参数可分为以下几种类型

1:文本类型:(包括文本转换型,列如:字符串“5”,目标需要是一个Integer,则可以转换)
2:Class类型: 直接通过反射方式newInstance方式构造参数对象
3:引用类型:容器通过一个Id获取另一个Bean的实例作为参数


1.4:怎么注入
上节谈到将容器参数注入到对象内部,那么是必须以对象所支持的方式放入,最直接有效的方式就是直接调用对象的方法,但是由于对象具有多样性,显然通过直接调用的方式显然是不太现实。
上图的方式,肯定行不现实,如果需要存在多个Bean类型,还不知道需要import多个类型呢,现在只能寻找一种非传统途径才能达到目标。在我们的JDK开发包中,就存在这么一种非传统方式:反射(感谢JDK的开发者们),可以在java.lang.reflect包下找到相应的API。下面列举一下反射技术将会用到的几个重要的类:

1: java.lang.Class
Java源文件被编译成二进制文件,虚拟机在运行的时候,将加载该二进制内容进内存,Java并以Class对象进行表征,我们可以比较容易获得该定义性对象。
A: 获取方式一,通过类的名字获得,例如:
Class clazz = Class.forName(“test.Man”) ;
B: 获取方式二,通过对象实例获得
Man man = new Man();
Class clazz = man.getClass();

2: java.lang.reflect.Constructor
Bean构造函数的定义对象,在Class对象上,可以获得构造函数的定义对象。
Class clazz = Class.forName(“test.Man”) ;
上图定义的类中包含两个构造函数,那么下面程序代码则可以获取对应的构造对象
Constructor constructor1 = clazz. getDeclaredConstructor(new Class[0])
Constructor constructor2 = clazz. getDeclaredConstructor(new Class[]{java.lang.String.class})

在得到构造函数之后,就可以在此基础上构建对象实例了
Man man1=(Man)constructor1.newInstance(new Object[0]);
Man man2=(Man)constructor2.newInstance(new Object[]{“Chris”});

3: java.lang.reflect.Field
Bean字段定义对象,如上图类中的 name属性,在Class对象上,可以获得成员字段的定义对象。
Field field = clazz. getDeclaredField (“name”);
通过字段对象.set方法,可以为对象成员字段赋值,但是由于当前字段是私有的,外部是可以不访问的,但是稍微做点改变,依然还是可以访问的。
field.setAccessible(true);
field.set(man1, “Chris”);

4:java.lang.reflect.Method;
Bean方法定义对象,如上图类中的 setName方法,在Class对象上,可以获得成员方法的定义对象。
Method method = clazz. getDeclaredMethod (“setName”, new Class[]{ava.lang.String.class } );
既然能得到方法的定义对象,那么就可以通过它为对象赋值
method.Invoke(man1,new Object[]{“Chris”} );

到此,我们已了解Java反射技术是如何将参数值放入对象内部的,这个是Ioc容器实现的重要基础。

1.5:容器指令
Bean容器之所以能准确构建我们需要的对象,并将参数注入其内部,那是因为容器得知了正确的指令(告诉容器该干什么),例如构建对象指令,注入指令等等,针对每个Bean,都有可能存在这些容器指令的,很明显这些指令是在围绕Bean对象进行的,并作为其组成部分存在于容器中。

1.6:定义指令
上一节中,我们探讨了容器指令的概念,并且了解指令的目标对象是Bean.那应指令到底有哪些呢?对于Ioc容器来说,一个重要指令就是:注入. 从1.4节中我们从反射技术探讨如何注入时,提到了注入有三种不同的方式,那么我们可以初略定义注入三个指令:1字段注入指令 2构造方法注入指令 3:方法调用注入指令。除了注入指令,那么还有没有其他指令呢?应该是有的,比如还可以定义:单例指令,方法拦截指令(AOP)等等,当然也可以根据具体的情况,定义需要的一些其他指令,下面给个指令列表罗列几个概要的

指令名                      指令内容                                 类别
字段注入指令         将参数值传给Bean的字段                         注入
构造方法注入指令 通过构造方法,将参数值传入Bean