靜態代理:
代理前,所有東西都已知
動態代理:
在代理之前,都是未知的
package jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JDKmeipo implements InvocationHandler {
private Person xiaoluo;
public Object getInstance(Person xiaoluo){
this.xiaoluo=xiaoluo;
Class<?> clazz=xiaoluo.getClass();
return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this::invoke);
}
//method就是測試時,調用方法的反射對象;
// 1拿到被代理類對象的引用,並獲取到所有接口,通過反射獲取,method就是測試時,調用方法的反射對象;
// 2JDK的Proxy通過newProxyInstance自動生成一個新類,該類實現被代理類所有方法
// 3動態生成JAVA代碼,把新加的業務邏輯通過一定的方式去調用
// Xiaoluo obj=(Xiaoluo) new Cglib58().getInstance(Xiaoluo.class);
// obj.findLove();
// 4編譯新生成的JAVA代碼.class
// 5再重新加載到JVM中
// 上述過程叫字節碼重組
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("==========");
method.invoke(this.xiaoluo,args);
System.out.println("==========");
return null;
}
}
自動生成的新類
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import jdk.Person;
public final class $Proxy0 extends Proxy implements Person {
private static Method m1;
private static Method m4;
private static Method m2;
private static Method m3;
private static Method m5;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void findLove() throws {
try {
super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void buyHouse() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void findJob() throws {
try {
super.h.invoke(this, m5, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2
) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m4 = Class.forName("jdk.Person").getMethod("findLove");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("jdk.Person").getMethod("buyHouse");
m5 = Class.forName("jdk.Person").getMethod("findJob");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
newInstance、invoke參數詳解
method就是測試時,調用方法的反射對象;
https://www.cnblogs.com/fengmingyue/p/6092151.html
JDK中動態代理,只能代理一個接口 InvocationHandler(cglib代理對象靈活,若代理接口,則使用代理其實現類的方式實現),否者報錯開頭的,通常是自動生成的
CGLIB
CGLib採用了非常底層的字節碼技術,其原理是通過字節碼技術爲一個類創建子類,並在子類中採用方法攔截的技術攔截所有父類方法的調用,順勢織入橫切邏輯。JDK動態代理與CGLib動態代理均是實現Spring AOP的基礎。
調用過程:代理對象調用this.setPerson方法->調用攔截器->methodProxy.invokeSuper->CGLIB$setPerson$0->被代理對象setPerson方法
cglib代理中需要的包
asm,cglib
asm框架解析
https://www.cnblogs.com/clds/p/4985893.html
代理模式作用:
AOP實現,攔截器,自己不想做但又不得不做的事的增強
**代理:**靜態、動態;代理角色、被代理的角色(目標對象)
性能比較
CGLib創建的動態代理對象性能比JDK創建的動態代理對象的性能高不少,Cglib動態代理執行代理方法效率之所以比JDK的高是因爲Cglib採用了FastClass機制,它的原理簡單來說就是:爲代理類和被代理類各生成一個Class,這個Class會爲代理類或被代理類的方法分配一個index(這裏的返回值,通過該返回值,查找對應的方法,即通過一個int參數,找到方法進行,最終在methodProxy.invokeSuper()執行方法
public int getIndex(Signature var1){
String var10000 = var1.toString();
switch(var10000.hashCode()) {
case -2071771415:
if (var10000.equals("CGLIB$clone$6()Ljava/lang/Object;")) {
return 23;
}
break;
case -2055565910:
if (var10000.equals("CGLIB$SET_THREAD_CALLBACKS([Lnet/sf/cglib/proxy/Callback;)V")) {
return 12;
}
break;
return -1;
}
)。這個index當做一個入參,FastClass就可以直接定位要調用的方法直接進行調用,這樣省去了反射調用,所以調用效率比JDK動態代理通過反射調用高。
參考:https://blog.csdn.net/weixin_33883178/article/details/92375100
但是CGLib在創建代理對象時所花費的時間卻比JDK多得多(JDK和Cglib都是在運行期生成字節碼,JDK是直接寫Class字節碼,Cglib(適用於單例模式)使用ASM框架寫Class字節碼,Cglib代理實現更復雜,生成代理類比JDK效率低。),所以對於單例的對象,因爲無需頻繁創建對象,用CGLib合適,反之,使用JDK方式要更爲合適一些。同時,由於CGLib由於是採用動態創建子類的方法,對於final方法,無法進行代理。
FastClass並不是跟代理類一塊生成的,而是在第一次執行MethodProxy invoke/invokeSuper時生成的並放在了緩存中。
如下可獲得反編譯獲得生成的類
package cglib;
import jdk.Person;
import net.sf.cglib.core.DebuggingClassWriter;
import sun.misc.ProxyGenerator;
import java.io.FileOutputStream;
public class CglibProxyTest {
public static void main(String[] args) {
try {
//只能實現接口的實現類
//獲得生成類 System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"D:\\IDEAWorkSpace\\proxy\\src\\$Cglib0.class");
Mingjie obj=(Mingjie) new Cglib58().getInstance(Mingjie.class);
obj.findLove();
}catch (Exception e){
e.printStackTrace();
}
//
}
}
總結
1.JDK動態代理是實現了被代理對象的接口,Cglib是繼承了被代理對象。
2.JDK和Cglib都是在運行期生成字節碼,JDK是直接寫Class字節碼,Cglib(適用於單例模式)使用ASM框架寫Class字節碼,Cglib代理實現更復雜,生成代理類比JDK效率低。
3.JDK調用代理方法,是通過反射機制調用,Cglib是通過FastClass機制直接調用方法,Cglib執行效率更高。
Cglib執行流程:
通過Hnhancer創建新生成的代理類(asm框架字節碼創建類)->
代理類繼承被代理類方法,當測試類中調用
Mingjie obj=(Mingjie) new Cglib58().getInstance(Mingjie.class);
obj.findLove();
類似下面的方法時,實際上調用的是新生成的代理類中的方法(即被代理類的子類的方法),子類方法中對應的findlove()內部,通過創建一個MethodIntercept對象,來調用intercept(…)方法->
這時intercept(…)中的methodProxy.invokeSuper(…)會被執行
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
try {
this.init();
MethodProxy.FastClassInfo fci = this.fastClassInfo;
//FastClass中有一個getIndex方法,參數是代理類和被代理類的signature簽名,會返回一個int值,通過int值,FastClass中的invoke方法,可以找到對應代理類方法
return fci.f2.invoke(fci.i2, obj, args);
} catch (InvocationTargetException var4) {
throw var4.getTargetException();
}
}
private static class FastClassInfo {
FastClass f1;//被代理類FastClass
FastClass f2;//代理類FastClass
int i1; //被代理類的方法簽名(index)
int i2;//代理類的方法簽名
private FastClassInfo() {
}
}
//MethodProxy invoke/invokeSuper都調用了init()
private void init() {
if(this.fastClassInfo == null) {
Object var1 = this.initLock;
synchronized(this.initLock) {
if(this.fastClassInfo == null) {
MethodProxy.CreateInfo ci = this.createInfo;
MethodProxy.FastClassInfo fci = new MethodProxy.FastClassInfo();
fci.f1 = helper(ci, ci.c1);//如果緩存中就取出,沒有就生成新的FastClass
fci.f2 = helper(ci, ci.c2);
fci.i1 = fci.f1.getIndex(this.sig1);//獲取方法的index
fci.i2 = fci.f2.getIndex(this.sig2);
this.fastClassInfo = fci;
this.createInfo = null;
}
}
}
}
,且同時生成兩個FastClass,與新生成的代理類和被代理類對應,FastClass中有一個getIndex方法,參數是代理類和被代理類的signature簽名,會返回一個int值,通過int值,得到對應的新生成的代理類方法。這時候,被代理類的方法就會被執行了。
策略模式
舉例
購物付款流程圖
目錄結構
創建訂單類:
Order.java
import pay.PayState;
import pay.PayType;
import pay.Payment;
public class Order {
private String uid;
private String orderId;
private double amount;
public Order(String uid,String orderId,double amount){
this.amount=amount;
this.orderId=orderId;
this.uid=uid;
}
public PayState pay(PayType payType){
return payType.get().pay(this.uid,this.amount);
}
}
數據持久類
Paystate.java
package pay;
public class PayState {
private int code;
private Object data;
private String msg;
public PayState(int code, Object data, String msg){
this.code=code;
this.data=data;
this.msg=msg;
}
@Override
public String toString() {
return ("支付狀態{" +
code +"}," +
msg +
", 交易詳情" + data);
}
}
定義接口
Payment.java
package pay;
public interface Payment {
public PayState pay(String uid, double amount);
}
實現接口
JdPay.java
package pay;
public class Jdpay implements Payment{
@Override
public PayState pay(String uid, double amount) {
System.out.println("京
東,開始扣款");
return new PayState(200,amount,"支付成功");
}
}
枚舉類:讓每一種支付方式可一直使用
Paytype.java
package pay;
public enum PayType {
Ali_Pay(new AliPay()),Jd_Pay(new Jdpay());
private Payment payment;
PayType(Payment payment){
this.payment=payment;
}
public Payment get(){
return this.payment;
}
}
測試類
import pay.Jdpay;
import pay.PayType;
public class Paytest {
public static void main(String[] args) {
Order order=new Order("1","1111111",333.3);
System.out.println(order.pay(PayType.Ali_Pay));
}
}
現在直接使用各支付方式支付,使用時,只需要在枚舉類中添加,代碼更健壯,更易修改、維護