jvm,類加載,反射java
Java語言是跨平臺語言,一段java代碼,通過編譯成class文件後,可以在不一樣系統的服務器上運行;由於java語言中有虛擬機jvm,纔有了跨平臺,java爲了實現跨平臺,在jvm上投入了很大的研發開發資源。jvm是java的底層,本文學習探討下java的jvm及關聯的類加載和反射知識數據庫
JVM是Java Virtual Machine(Java虛擬機)的縮寫,JVM是一種用於計算設備的規範,它是一個虛構出來的計算機,是經過在實際的計算機上仿真模擬各類計算機功能來實現的。編程
Java語言的一個很是重要的特色就是與平臺的無關性。而使用Java虛擬機是實現這一特色的關鍵。通常的高級語言若是要在不一樣的平臺上運行,至少須要編譯成不一樣的目標代碼。而引入Java語言虛擬機後,Java語言在不一樣平臺上運行時不須要從新編譯。Java語言使用模式Java虛擬機屏蔽了與具體平臺相關的信息,使得Java語言編譯程序只需生成在Java虛擬機上運行的目標代碼(字節碼),就能夠在多種平臺上不加修改地運行。Java虛擬機在執行字節碼時,把字節碼解釋成具體平臺上的機器指令執行。 [1]json
jvm的構成安全
jvm週期:是在java程序執行時運行,程序結束時中止服務器
jvm的基本結構有:類加載子系統、本地方法棧、Java棧、方法區、Java堆、pc寄存器,垃圾回收,執行引擎框架
java是面嚮對象語言,邏輯代碼中的類文件執行邏輯前,是須要jvm讀取class文件並校驗初始化後才能使用的,包括變量,方法,構造。dom
類加載系統能夠認爲是在使用到java對像時(抽象),對java對象字節碼的讀取加載預編譯(具體),以後再也不加載(讀取校驗一次)。jvm
棧是先進後出的結構,java棧時一塊線程私有的內存空間,能夠理解爲一個java線程對應一個java棧,棧和線程密切關聯,棧包含線程運行的實時信息,如當前運行方法地址,方法中的瞬時變量等信息ide
在一個jvm實例的內部,類型信息被存儲在一個稱爲方法區的內存邏輯區中。類型信息是由類加載器在類加載時從類文件中提取出來的。類(靜態)變量也存儲在方法區中。
java堆是和應用程序關係最爲密切的內存空間,幾乎全部的對象都存放在堆上。而且java堆是徹底自動化管理的,經過垃圾回收機制,垃圾對象會被自動清理,而不須要顯示的釋放。
存放計算機下一步要執行的指令的地址,
由於程序運行沒建立一個對象都須要使用硬件的內存資源,不能無限使用,jvm的垃圾回收可以自動回收再也不使用的java對象,使內存空間有效利用。垃圾回收線程是後臺執行的,不須要認爲回收內存垃圾,即便有垃圾回收方法調用,但並不能控制jvm如何去將一個對象失效回收。
Java 字節碼指令指向特定邏輯得本地機器碼,而JVM 解釋執行Java字節碼指令時,會直接調用字節碼指向得本地機器碼;
java底層由C語言編寫,執行java程序時,jvm每讀取一個字節碼指令動做,執行引擎就解析解釋執行本地系統對應的本地機器碼。
虛擬機把描述類的數據從 Class 文件加載到內存,並對數據進行校驗、轉換解析和初始化,最終造成能夠被虛擬機直接使用的 Java 類型,這就是虛擬機的類加載機制。
在Java語言裏面,類型的加載、鏈接和初始化過程都是在程序運行期間完成的
做爲軟件開發語言,java在安全方面也有很高的要求,因此類加載是有一套規則的,jre是java運行時的環境,包括不少基本類,如java.lang.String 是字符串類,這個類很基礎也很重要,那在加載的時候不能容許加載的String類被篡改,java保證類加載安全,首先看是否已經加載,若是沒有查看核心庫是否有此類,沒有此類纔會去擴展環境找類文件加載,這種機制保證了類在加載時的惟一性和安全性。
java類加載通常來講是詢問本身的parentClassLoader 加載,若是沒有加載成功,才本身加載,加載順序是自上而下
java.lang.ClassLoader 加載類方法
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded Class<?> c = findLoadedClass(name); //0.是否已加載 if (c == null) { long t0 = System.nanoTime(); try { if (parent != null) { c = parent.loadClass(name, false); //1.沒有加載,首先經過父類加載器加載 } else { c = findBootstrapClassOrNull(name); //1.沒有父類加載器時加載方式 } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader } if (c == null) { // If still not found, then invoke findClass in order // to find the class. long t1 = System.nanoTime(); c = findClass(name); //若是父類沒有加載到類,則使用findClass方法去加載類(這個方法能夠重寫自定義) // this is the defining class loader; record the stats sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } } if (resolve) { resolveClass(c); } return c; } }
反射是Java重要的技術點,在框架開發,AOP切面編程代理等方面都須要反射方面的技術去實現。
Java反射機制主要提供瞭如下功能:
Class 類的字節碼對象
Field 類的屬性
Method 類的方法
Constructor 類的構造方法
Annotation 類(方法字段)的註解
模擬事務的註解
@Target({ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited public @interface defTransaction { }
普通封裝對象
public interface People { String getName(); void setName(String name); Integer getAge(); void setAge(Integer age); BigDecimal getMoney(); void setMoney(BigDecimal money); @defTransaction void addMoney(BigDecimal addNum); @defTransaction void subTractMoney(BigDecimal subNum); }
public class TestPeople implements People{ // 姓名 public String name; // 年齡 private Integer age; // 錢 private BigDecimal money; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public BigDecimal getMoney() { return money; } public void setMoney(BigDecimal money) { this.money = money; } @Override public void addMoney(BigDecimal addNum) { this.money = this.money.add(addNum); } @Override public void subTractMoney(BigDecimal subNum) { this.money = this.money.subtract(subNum); } }
反射測試類
public class ReflectTest { public static void main(String[] args) { // 普通對象建立 使用new People testPeople = new TestPeople(); testPeople.setName("Frank"); testPeople.setAge(18); testPeople.setMoney(new BigDecimal(10)); System.out.println("json:" + JsonUtil.objectToJson(testPeople)); // 反射建立對象 class.newInstance() ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); try { Class<?> clazz = contextClassLoader.loadClass("com.domoment.leaves.common.util.reflect.TestPeople"); if(clazz != null) { Object people = clazz.newInstance(); System.out.println("newInstance start json:" + JsonUtil.objectToJson(people)); // 經過反射執行方法 Method setName = clazz.getMethod("setName", String.class); setName.invoke(people, "inoverFrank"); System.out.println("newInstance end json:" + JsonUtil.objectToJson(people)); } } catch (Exception e) { e.printStackTrace(); } } }
代理類DefProxy (People是被代理類)
public class DefProxy implements InvocationHandler{ // 這個就是咱們要代理的真實對象 private Object subject; // 構造方法,給咱們要代理的真實對象賦初值 public DefProxy(Object subject){ this.subject = subject; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Annotation[] annotations = method.getDeclaredAnnotations(); boolean transactionOpen = false; for (Annotation annotation : annotations) { if(annotation instanceof defTransaction) { transactionOpen = true; break; } } if(transactionOpen) { //當方法上有 defTransaction 註解時,執行方法前開啓事務 System.out.println("open Transaction"); } System.out.println("proxy:" + method.getName()); Object result = method.invoke(subject, args); if(transactionOpen) { //當方法上有 defTransaction 註解時,執行方法後關閉事務 System.out.println("close Transaction"); } return result; } }
代理測試代碼
public class ReflectTest { public static void main(String[] args) { // 反射建立對象 ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); try { Class<?> clazz = contextClassLoader.loadClass("com.domoment.leaves.common.util.reflect.TestPeople"); if(clazz != null) { Object people = clazz.newInstance(); System.out.println("newInstance start json:" + JsonUtil.objectToJson(people)); Method setName = clazz.getMethod("setName", String.class); setName.invoke(people, "inoverFrank"); System.out.println("newInstance end json:" + JsonUtil.objectToJson(people)); InvocationHandler handler = new DefProxy(people); // 構造代理對象 People proxyPeople = (People)Proxy. newProxyInstance(handler.getClass().getClassLoader(), people.getClass().getInterfaces(), handler); proxyPeople.setName("proxySetFrank"); proxyPeople.setAge(20); proxyPeople.setMoney(new BigDecimal(999)); System.out.println("proxyPeople end json:" + JsonUtil.objectToJson(people)); proxyPeople.addMoney(new BigDecimal(20)); System.out.println("proxyPeople add json:" + JsonUtil.objectToJson(people)); proxyPeople.subTractMoney(new BigDecimal(17)); System.out.println("proxyPeople end json:" + JsonUtil.objectToJson(people)); } } catch (Exception e) { e.printStackTrace(); } } }
控制檯打印
newInstance start json:{} newInstance end json:{"name":"inoverFrank"} proxy:setName proxy:setAge proxy:setMoney proxyPeople end json:{"name":"proxySetFrank","age":20,"money":999} open Transaction proxy:addMoney close Transaction proxyPeople add json:{"name":"proxySetFrank","age":20,"money":1019} open Transaction proxy:subTractMoney close Transaction proxyPeople end json:{"name":"proxySetFrank","age":20,"money":1002}
能夠看到方法上有 defTransaction 註解的時候,
方法執行前 打印 open Transaction
方法執行後 打印 close Transaction
這是模擬,真實場景就能夠將打印改成代理時擴展方法,如數據庫操做時候,開啓關閉事務