Spring的IOC
IOC(控制反转:Inverse of Control)是Spring容器的内核,AOP、声明式事务都在此基础上开花结果。IOC不够开门见山,Martin Fowler提出DI(Dependency Injection)
概念用来代替IOC,即让调用类的某一接口实现类的依赖关系(取得)由第三方(容器)注入,以移除调用类都某一接口实现类的依赖。
Spring的IOC主要有属性注入、构造函数注入、接口注入(将调用类所有的依赖注入的方法都抽取到一个接口中,调用类通过实现改接口提供相应的注入方法,不常用),这里就不具体介绍了。
Spring的IOC的技术实现得益于Java的反射机制,很多概念之所以理解着不容易,我个人觉得一个概念不容易理解,但是如果知道这个概念到底具体指什么,就很容易理解了。 写一个测试类:
package test; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import module2.vo.FtcspSecUser; /** * @author 冯 * */ public class ReflectTest { public static FtcspSecUser initByDefalutCons() throws Throwable{ //通过类装载器获取User类在JVM中的对象表示。 ClassLoader loader = Thread.currentThread().getContextClassLoader(); Class clazz = loader.loadClass("module2.vo.FtcspSecUser"); //获取类的默认构造器对象,并通过它实例化User对象。 Constructor cons = clazz.getConstructor((Class[])null); FtcspSecUser user = (FtcspSecUser)cons.newInstance(null); //通过反射方法设置属性。 Method setLoginName= clazz.getMethod("setLoginName", String.class); setLoginName.invoke(user, "小北风"); Method setUserName = clazz.getMethod("setUserName",String.class); setUserName.invoke(user, "xiaofeng"); return user; } public static void main(String[] args) throws Throwable{ FtcspSecUser user = initByDefalutCons(); System.out.println("-----根据反射注入 loginName,userName------"); System.out.println("-----loginName------"+user.getLoginName()); System.out.println("-----userName-------"+user.getUserName()); } }
要理解这个测试类,你还要理解Class对象和类装载器这两个概念。
以前也了解过着两个东西,但是理解的模模糊糊不知干什么用的也不知道具体到底指什么。我还记得在毕业的时候看过一篇写类装载器的blog,现在回头想想作者写的不错,但是我不知道是干什么用的,仅此而已!很多东西只有到了用到,知道具体是做什么的,理解起来才,水到渠成吧。
有关Class对象。
首先必须知道的是我们的Java类必须被编译成.class文件加载到JVM中,被JVM解释才能运行,这个和C++编译成二进制码加载到内存中才能运行是一个道理。JVM启动的时候,类装载器就去寻找字节码文件并构造出在JVM内部表示的对象组件。通俗一点说,Class是一个类(就如同FtcspSecUser一样),JVM把字节码加载进内存的时候实例化一个Class对象来表示这个加载到内存中二进制文件(也是我们的Java类),这个JVM内部表示的对象组件应该就是Class的一个对象,Class也是一个类(这货还是一个关键字)。
这个在JVM中Class对象,描述了我们的Java类的元信息(描述信息的信息)。通过这对象,我们可以知道Java类的结构信息:如构造函数、属性和方法。Java允许我们借由这个元信息对象(Java类在JVM中的Class实例),间接调用Class对象的功能(例子中的Method.invoke(user, "小北风")方法),这就是Java反射的基础,亲们!
有关类装载器。
在Java中,类装载器把一个类装载进入JVM,需要经过一下步骤:
- 装载:查找和导入.class文件
- 链接:执行校验、准备和解析步骤
a)校验:检查载入class文件的正确性
b)准备:给类的静态变量分配存储区域
c)解析:将符号引用转换成直接引用(和C++的链接一样)
- 态代码块初始化:对类的静态变量和静执行初始化工作
那么具体什么是类装载器呢?它做了这么重要的工作。
类装载器就是ClassLoader和它的子类,是一个重要的Java运行时系统组件(组件尼玛大部分情况下就是类),负责查找和装入字节码文件。
JVM中的ClassLoader:根装载器,ExtClassLoader(扩展类装载器)和AppClassLoader(系统类装载器)。
其中根装载器不是ClassLoader的子类,是由C++编写的,它负责加载JRE的核心类库:rt.jar、charsets.jar等等;ExtClassLoader负责装载JRE扩展目录ext中的jar包;AppClassLoader负责装载应用程序的类。写一个测试一下:
ClassLoader loader = Thread.currentThread().getContextClassLoader(); System.out.println("----currentLoader---"+loader); System.out.println("----parentLoader----"+loader.getParent()); System.out.println("----grandParentLoader---"+loader.getParent().getParent()); =========result========== ----currentLoader---sun.misc.Launcher$AppClassLoader@9d8643e ----parentLoader----sun.misc.Launcher$ExtClassLoader@5d9d277e ----grandParentLoader---null
最后一个装载器是根装载器,由于Java无法获取其句柄,所以返回null。
JVM装载器的全盘负责委托机制:全盘负责机制是指但ClassLoader装载一个类的时候,除非显示的使用另外一个ClassLoader,该类说依赖和应用的类(感觉依赖和引用是一个意思)也由这个ClassLoader载入;委托机制是指先委托父装载器寻找目标类,只有在父装载器找不到的情况下,才从自己的类路径中查找并载入(这一点处于安全考虑,如果你也写了一个java.lang.String,加载进JVM的永远是根加载器载如的类库中的String),类加载器返回的对象就是JVM中对应类的java.lang.Class类的一个实例。
java.lang.Class没有public的构造方法,Class对象是在类装载的时候由JVM调用ClassLoader的defineClass()自动构造的。
我们在写连接数据的时候需要手动的去把Oracle的jdbc驱动加载到JVM中,就是Class.forName("oracle.jdbc.driver.OracleDriver")。以前真的不知道为什么要来这么一句代码,干鸟用的。
AppClassLoader应该可以在引用的地方把它加载进JVM才对啊,为什么还要我们手动去加载?这个应该是DriverManager的原因。Jdbc提供的DriverManager用于跟踪所有可以的Jdbc驱动,但是这个跟踪不是自动的(应该是没有应用到,DriverManager直接去查找),需要Driver类(oracle驱动、mysql驱动)自己在DriverManager上注册。怎么注册?哈哈,就是在驱动类加载到JVM的时候,执行静态初始化工作(类加载器加载类到JVM的步骤,对上了吧?而Driver类的静态初始化工作,就是在DriverManager上进行注册),否则DriverManager找不到驱动。这个和依赖引用到某个类,然后把它加载到JVM有点不太一样哦。
加载器的接口
Class loadClass(String name)
Class defineClass(String name,byte[] b,int off,int len)
这个方法将类文件的字节码转换成JVM内部的java.lang.Class对象(我们的元信息),字节数组可以从本地文件系统、远程网络获取。name是字节数组对应的全限定类名。
Class findLoadedClass(String name)
ClassLoader getParentLoader();
上面的这些都是Class的静态方法(最后一个不是)。哈哈
截个图更清楚一些哈
下一篇写一些反射的接口和Spring资源加载的一些基础。