Java jvm 類加載 反射

Java 底層

jvm,類加載,反射java

Java語言是跨平臺語言,一段java代碼,通過編譯成class文件後,可以在不一樣系統的服務器上運行;由於java語言中有虛擬機jvm,纔有了跨平臺,java爲了實現跨平臺,在jvm上投入了很大的研發開發資源。jvm是java的底層,本文學習探討下java的jvm及關聯的類加載和反射知識數據庫

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線程對應一個java棧,棧和線程密切關聯,棧包含線程運行的實時信息,如當前運行方法地址,方法中的瞬時變量等信息ide

方法區

在一個jvm實例的內部,類型信息被存儲在一個稱爲方法區的內存邏輯區中。類型信息是由類加載器在類加載時從類文件中提取出來的。類(靜態)變量也存儲在方法區中。

Java堆

java堆是和應用程序關係最爲密切的內存空間,幾乎全部的對象都存放在堆上。而且java堆是徹底自動化管理的,經過垃圾回收機制,垃圾對象會被自動清理,而不須要顯示的釋放。

pc寄存器

存放計算機下一步要執行的指令的地址,

垃圾回收

由於程序運行沒建立一個對象都須要使用硬件的內存資源,不能無限使用,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

這是模擬,真實場景就能夠將打印改成代理時擴展方法,如數據庫操做時候,開啓關閉事務

相關文章
相關標籤/搜索