• Spring -- 3.0


         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资源加载的一些基础。

  • 相关阅读:
    动态规划
    关键路径
    拓扑排序
    最小生成树
    Floyd 多源最短路径
    SPFA算法
    Bellman_Ford算法(负环的单源路径)
    Dijkstra算法
    fill和memset的区别
    Codeforces Round #655 (Div. 2) 题解
  • 原文地址:https://www.cnblogs.com/lovery/p/3691520.html
Copyright © 2020-2023  润新知