我們可能都用過 Spring AOP ,底層的實現原理是怎樣的呢?java
反射經常使用於編寫工具,企業級開發要用到的 Mybatis、Spring 等框架,底層的實現都用到了反射。能用好反射,就能提升咱們編碼的核心能力。框架
JAVA反射機制是在運行狀態中,對於任意一個實體類,都可以知道這個類的全部屬性和方法;對於任意一個對象,都可以調用它的任意方法和屬性。ide
做用:函數
經常使用的類:工具
Class 類的實例表示正在運行的 Java 應用程序中的類和接口,Class 沒有公共構造方法,Class 對象是在加載類時由 Java 虛擬機及經過調用類加載器中的 defineClass 方法自動構造的。測試
獲取 Class 對象有4種方式,前三種比較經常使用。this
首先建立一個類用於測試編碼
package com.jikedaquan.reflection; public class User { private int id; private String username; private String password; public User() { } public User(int id, String username, String password) { super(); this.id = id; this.username = username; this.password = password; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public void show() { System.out.println("Hello"); } @Override public String toString() { return "User [id=" + id + ", username=" + username + ", password=" + password + "]"; } }
編寫測試代理
package com.jikedaquan.reflection; public class GetClass { public static void main(String[] args) { //方法1 try { Class clz1=Class.forName("com.jikedaquan.reflection.User"); } catch (ClassNotFoundException e) { e.printStackTrace(); System.out.println("找不到指定類"); } //方法2 Class clz2=User.class; //方法3 User user=new User(); Class clz3=user.getClass(); //方法4 類的加載器 try { Class clz4=GetClass.class.getClassLoader().loadClass("com.jikedaquan.reflection.User"); } catch (ClassNotFoundException e) { e.printStackTrace(); System.out.println("找不到指定類"); } } }
方法1語法:
Class Class對象 = Class.forName(包名+類名);
code
方法2語法:
Class Class對象 = 類名.class;
方法3語法:
Class Class對象 = 對象.getClass();
getClass() 方法是從 Object 類中繼承過來的
Class 類經常使用方法
方法名稱 | 說明 |
---|---|
Annotation[] getAnnotations() | 返回此元素上存在的全部註解 |
Constructor
|
獲取指定參數的構造函數 |
Constructor<?>[] getConstructors() | 返回包含的公有構造方法 |
Constructor<?>[] getDeclaredConstructors() | 返回全部構造方法 |
Field getDeclaredField(String name) | 返回一個 Field 對象,該對象反映此 Class 對象所表示的類或接口的指定已聲明字段 |
Method getDeclaredMethod(String name, Class<?>... parameterTypes) | 根據方法名和參數獲取方法對象 |
API 中能夠看到有兩種獲取結構的方式:getDeclaredXxx()和getXxx();getDeclaredXxx()能夠獲取全部包括私有的
獲取類的結構
package com.jikedaquan.reflection; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; public class GetClassStruct { public static void main(String[] args) { try { Class clz=Class.forName("com.jikedaquan.reflection.User"); System.out.println("===========構造==========="); //獲取構造方法 Constructor[] cons=clz.getDeclaredConstructors(); for (Constructor constructor : cons) { System.out.println(constructor); } //獲取字段 System.out.println("===========字段==========="); Field[] fields=clz.getDeclaredFields(); for (Field field : fields) { System.out.println(field); } //獲取方法 System.out.println("===========方法==========="); Method[] methods=clz.getDeclaredMethods(); for (Method method : methods) { System.out.println(method); } //獲取父類 System.out.println("===========父類==========="); Class supperClass=clz.getSuperclass(); System.out.println(supperClass.getName()); //獲取實現的接口 System.out.println("===========接口==========="); Class[] interfaces=clz.getInterfaces(); for (Class interf : interfaces) { System.out.println(interf); } //獲取註解 System.out.println("===========註解==========="); Annotation[] annotations=clz.getAnnotations(); for (Annotation annotation : annotations) { System.out.println(annotation); } } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
注意:jdk1.9棄用此方式實例化對象
Object obj=clz.newInstance();
經過反射獲取有參或無參構造後方可實例化化對象
package com.jikedaquan.reflection; import java.lang.reflect.Constructor; public class CallConstructor { public static void main(String[] args) { //獲取User 的 Class Class<User> clz=User.class; //獲取無參構造方法並實例化 try { //getConstructor()方法不傳參即無參 Constructor<User> constructor=clz.getConstructor(); User user=constructor.newInstance(); System.out.println(user); } catch (Exception e) { e.printStackTrace(); } //獲取有參構造方法並實例化 try { Constructor<User> constructor=clz.getConstructor(int.class,String.class,String.class); User user=constructor.newInstance(18,"張三","abc123"); System.out.println(user); } catch (Exception e) { e.printStackTrace(); } } }
獲取指定構造方法時,第二個參數爲動態參數,不填寫即獲取無參構造方法,填寫指定個數和指定類型.class可獲取對應方式的構造方法。
package com.jikedaquan.reflection; import java.lang.reflect.Method; public class CallMethod { public static void main(String[] args) { //獲取User 的 Class Class<User> clz=User.class; //獲取無參方法 show try { Method method=clz.getMethod("show"); //執行clz中的方法 method.invoke(clz.getConstructor().newInstance()); } catch (Exception e) { e.printStackTrace(); } //獲取一個參數爲String的方法 try { Method method=clz.getMethod("setUsername", String.class); //反射實例化對象 User user=clz.getConstructor().newInstance(); //執行這個對象的方法 method.invoke(user, "反射"); //測試結果 System.out.println(user); } catch (Exception e) { e.printStackTrace(); } } }
若是有多個參數,獲取方法:
getMethod("方法名稱",參數1.class,參數2.class,參數3.class)
多個參數執行時:
method.invoke(對象,參數1,參數2,參數3);
動態代理是指客戶經過代理類來調用其餘對象的方法,而且是在程序運行時根據須要建立目標類的代理對象。
原理:
使用一個代理將對象包裝起來,而後用該代理對象取代原對象,任何對原始對象的調用都要經過dialing,代理對象決定是否以及什麼時候將方法調用轉到原始對象上。
生活中海外代購其實就用到了代理,你可能不方便出國,可是代購能夠,最終幫你完成購買行爲。
以代購爲例子完成靜態代理
package com.jikedaquan.reflection; //購買接口(約定) interface Buy{ void buyProduct(); } //被代理的 class Customer implements Buy{ @Override public void buyProduct() { System.out.println("購買商品"); } } //代理 class ProxyBuy implements Buy{ private Customer customer; public ProxyBuy(Customer customer) { this.customer=customer; } @Override public void buyProduct() { System.out.println("代理:出國"); //被代理的對象的行爲 customer.buyProduct(); System.out.println("代理:回國"); } } public class TestStaticProxy { public static void main(String[] args) { Customer customer=new Customer(); ProxyBuy proxyBuy=new ProxyBuy(customer); proxyBuy.buyProduct(); } }
那麼動態代理意味着不能只代理 Customer 類的行爲,還能夠代理其餘類的行爲
package com.jikedaquan.reflection; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; //工廠接口 interface Factory{ void product(); } //電腦工廠 class ComputerFactory implements Factory{ @Override public void product() { System.out.println("生產電腦"); } } //動態代理處理器 class MyInvocationHandler implements InvocationHandler{ //要被代理的對象 private Object proxyObj; //產生代理對象 public Object bind(Object proxyObj) { this.proxyObj=proxyObj; return Proxy.newProxyInstance( proxyObj.getClass().getClassLoader(), proxyObj.getClass().getInterfaces(), this ); } //代理對象實際執行的方法 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("代理:收收費"); Object result=method.invoke(proxyObj, args); System.out.println("代理:代理完成"); return result; } } public class TestDynamicProxy { public static void main(String[] args) { //建立代理對象生產器 MyInvocationHandler invocationHandler=new MyInvocationHandler(); //建立要被代理的對象 ComputerFactory computerFactory=new ComputerFactory(); //生產代理對象 Object factoryProxy=invocationHandler.bind(computerFactory); Factory factory=(Factory) factoryProxy; factory.product(); //建立另外一個要被代理的對象(上個示例靜態代理的對象和接口) Customer customer=new Customer(); //生產代理對象 Object buyProxy=invocationHandler.bind(customer); Buy buy=(Buy) buyProxy; buy.buyProduct(); } }
在 main 方法中,建立了一個 MyInvocationHandler 對象,經過 bind 方法能夠傳入任意要被代理的對象,實現了動態。
重點來了,拿好小本子筆記!!!!!
實現動態代理的步驟:
1.建立要被代理的類的接口
2.建立要被代理的類實現類
3.建立代理對象處理器(MyInvocationHandler),實現 InvocationHandler 接口
4.編寫生產代理對象的方法,方法內調用 Proxy.newInstance() 方法,返回代理對象
5.重寫 InvocationHandler 的 invoke 方法
6.測試:建立代理對象生產器,生產代理對象