代码审计之代理

代理

代理是指通过代理对象来代替对真实对象(real object)的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。就相当于客户租房,房东没时间带客户看房,于是出租中介,中介去带客户看房租房。

image-20240514081400676

1. 静态代理

image-20240514191629575

元素组成

接口:定义行为和规范

被代理类:是目标对象

代理类:进行功能增强

1.1 静态代理实现

接口:

/**
 * 接口
 */
public interface IHouseServer {
    String address(String address);
}

目标类:

/**
 * 房东类为目标类
 */
public class Landlord implements IHouseServer{
    @Override
    public String address(String address) {
        System.out.println("我有一个房子要出租,它的地址是:"+address);
        return null;
    }
}

代理类:

/**
 * 中介类为代理类
 */
public class Intermediary implements IHouseServer{
    private Landlord landlord;
    //获取被代理的目标
    public Intermediary(Landlord landlord) {
        this.landlord = landlord;
    }
    @Override
    public String address(String address) {
        //增强操作
        System.out.println("与租户进行联系,并对租房者介绍房子");
        //目标操作
        landlord.address(address);
        //增强操作
        System.out.println("我需要收取一个月中介费");
        return null;
    }
}

1.2 静态代理存在的问题

  • 不利于代码拓展,接口中新建方法,每个实现类都要去添加方法
  • 代理对象需要创建好多,设计比较麻烦

2. 动态代理

2.1jak动态代理

接口:

/**
 * 接口
 */
public interface IHouseServer {
    String address(String address);
}

目标类:

/**
 * 房东类为目标类
 */
public class Landlord implements IHouseServer{
    @Override
    public String address(String address) {
        System.out.println("我有一个房子要出租,它的地址是:"+address);
        return null;
    }
}

动态生成代理及调用:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class TestjdkAgent {
    public static void main(String[] args) {
        IHouseServer proxy = (IHouseServer) Proxy.newProxyInstance(TestjdkAgent.class.getClassLoader(), Landlord.class.getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("与租户进行联系,并对租房者介绍房子");		//功能增强
                        Object ret = method.invoke(new Landlord(),args);
                        System.out.println("我要收取一个月的中介费");					//功能增强
                        return ret;
                    }
                }
        );

        proxy.address("房子的地址是xx市,某某区");
    }
}

以上动态代理的实现完成

  • Proxy:代理实例,可以通过newProxyInstance创建代理实例

    • getClassLoader类加载器,可以通过任意一个类进行获取
    • Class[],目标类所实现的接口
    • InvocationHandler:方法拦截器,可以在里面实现方法(功能增强)
  • Method:通过反射的方式执行目标方法

  • args:参数数组

字节码生成:

import sun.misc.ProxyGenerator;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class TestjdkAgent {
    public static void main(String[] args) throws Exception {
        IHouseServer proxy = (IHouseServer) Proxy.newProxyInstance(Landlord.class.getClassLoader(), Landlord.class.getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("与租户进行联系,并对租房者介绍房子");
                        Object ret = method.invoke(new Landlord(),args);
                        saveProClass("D:\\Code\\javaCode\\ProxyDemo\\src\\");
                        return ret;
                    }
                }

        );

        proxy.address("房子的地址是xx市,某某区");

    }

    /**
     * 使用来生成字节码
     * @param path
     */
    private static void saveProClass(String path) throws Exception {
        byte[] $proxy1s = ProxyGenerator.generateProxyClass("$Proxy1",Landlord.class.getInterfaces());
        FileOutputStream out = new FileOutputStream(new File(path+"$Proxy1.class"));
        out.write($proxy1s);
        if(out != null){
            out.flush();
            out.close();
        }
    }
}

生成的代码字节码反编译

//
// 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;

public final class $Proxy1 extends Proxy implements IHouseServer {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public $Proxy1(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 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 String address(String var1) throws  {
        try {
            return (String)super.h.invoke(this, m3, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    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"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("IHouseServer").getMethod("address", Class.forName("java.lang.String"));
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

  • 文字说明:
    • 通过实现接口,获取到接口里面的方法
    • 通过Proxy创建代理类实例
    • 通过反射机制,获取到一个个的方法对象
    • 调用InvocationHandler接口中的invoke方法,从而实现业务的增强

2.2CGLIB动态代理

接口:

package org.example;

public interface IHouseServer {
    String address(String address);
}

目标类:

package org.example;

public class Landlord implements IHouseServer{
    @Override
    public String address(String address) {
        System.out.println("我有一个房子要出租,它的地址是:"+address);
        return null;
    }
}

调用及生成目标代理类:

package org.example;

import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

//TIP To <b>Run</b> code, press <shortcut actionId="Run"/> or
// click the <icon src="AllIcons.Actions.Execute"/> icon in the gutter.
public class Main {
    public static void main(String[] args) {
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"D:\\Code\\javaCode\\Cglib_Proxy\\src\\main\\java\\org\\example\\");

        //使用CGLIB框架生成目标类的子类(代理类)实现增强
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Landlord.class);
//
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("与租户进行联系,并对租房者介绍房子");
                Object ret = methodProxy.invokeSuper(o,objects);
                System.out.println("我要收取一个月的中介费");
                return ret;
            }
        });
        Landlord iHouseServer = (Landlord)enhancer.create();
        iHouseServer.address("房子的地址是xx市,某某区");
    }
}
  • 文字说明
    • 通过继承的方式去获取到目标对象的方法
    • 通过传递方法拦截器MethodInterceptor实现方法拦截,在里面做具体增强
    • 调用生成的代理类对象具体执行重写的save方法,直接去调用方法拦截器里面的intercept方法
    • 前后加上增强操作,从而实现了不修改代码实现业务增强
代理类型实现机制回调方式使用场景效率
JDK动态代理通过实现接口,通过反射机制获取到接口里面的方法,并且自定义InvocationHandler接口,实现方法拦截调用 invoke 方法实现增强目标类有接口实现1.8高于CGLIB
CGLIB动态代理继承机制,通过继承重写目标方法,使用Methodlnterceptor 调用父类的目标方法从而实现代理调用interceptor方法不能使用final修饰的类和方法第一次调用生成字节码比较耗时间,多次调用性能还行

学习链接:06-cglib 动态代理_哔哩哔哩_bilibili

      | 1.8高于CGLIB                                     |

| CGLIB动态代理 | 继承机制,通过继承重写目标方法,使用Methodlnterceptor 调用父类的目标方法从而实现代理 | 调用interceptor方法 | 不能使用final修饰的类和方法 | 第一次调用生成字节码比较耗时间,多次调用性能还行 |

学习链接:06-cglib 动态代理_哔哩哔哩_bilibili

  • 14
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值