zoukankan      html  css  js  c++  java
  • 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资源加载的一些基础。

  • 相关阅读:
    HDU 5791 Two (DP)
    POJ 1088 滑雪 (DPor记忆化搜索)
    LightOJ 1011
    POJ 1787 Charlie's Change (多重背包 带结果组成)
    HDU 5550 Game Rooms (ccpc2015 K)(dp)
    HDU 5542 The Battle of Chibi (ccpc 南阳 C)(DP 树状数组 离散化)
    HDU 5543 Pick The Sticks (01背包)
    HDU 5546 Ancient Go (ccpc2015南阳G)
    NB-IoT的DRX、eDRX、PSM三个模式 (转载,描述的简单易懂)
    MQTT 嵌入式端通讯协议解析(转)
  • 原文地址:https://www.cnblogs.com/lovery/p/3691520.html
Copyright © 2011-2022 走看看