代理模式、策略模式

静态代理:
代理前,所有东西都已知
动态代理:
在代理之前,都是未知的

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代理对象灵活,若代理接口,则使用代理其实现类的方式实现),否者报错proxy0nJDKproxy0-n JDK中有规范,开头的,通常是自动生成的

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));
    }
}

现在直接使用各支付方式支付,使用时,只需要在枚举类中添加,代码更健壮,更易修改、维护

代理角色、被代理的角色(目标对象)

策略模式:只有选择权(注重可扩展)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章