深入理解java代理

##一文彻底搞懂java动态代理

为什么要使用代理

代理模式,是设计模式的一种,旨在增强某个类的功能。

现代编程,提倡高内聚低耦合。当想对已有模块增加功能时,要尽可能不动或者少动原代码。代理模式,提供了很好的解决方案。通过静态代理或动态代理,生成一个新的类,与被代理类产生关联,从而实现被代理类的功能增强。

代理的基本思想

1、代理类与被代理类实现同一个接口,或继承同一个父类;

2、代理类实现被代理类的功能;

3、代理类实现增强功能;

4、执行代理类。

静态代理

public interface ParentInterface
{
    void doSome();
}

public class TargetClass implements ParentInterface
{
    @Override
    public void doSome(){
      System.out.println("I'm original object!");
    }
}

public class ProxyClass implements ParentInterface
{
    TargetClass targetClass = new TargetClass();
    @Override
    public void doSome(){
      targetClass.doSome();
      System.out.println("I hava more functions!");
    }
}

动态代理

工作原理:

1、通过反射技术(JDK动态代理)、字节码技术,实现被代理类的所有接口和父类,动态生成目标类的代理类;

2、在代理类中增强目标类的功能;

3、动态加载代理对象,执行目标方法。

JDK动态代理

基本原理:

引入jdk的java.lang.reflect包,创建代理类,实现java.lang.reflect.InvocationHandler接口,重写invoke方法。

代理类

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

public class JdkProxyClass<T> implements InvocationHandler {
    private T target;

    public JdkProxyClass(T target) {
        this.target = target;
    }

    /**
     * 获取被代理接口实例对象
     * @param
     * @return
     */
    public <T>T getProxy() {
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("this is my function");
        Object result = method.invoke(target, args);
        System.out.println("my function done");
        return result;
    }
}

测试类

public class JdkProxyTest {
    public static void main(String[] args) {
        // 保存生成的代理类的字节码文件
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        // jdk动态代理测试
        ParentInterface subject = new JdkProxyClass<>(new TargetClass()).getProxy();
        subject.doSome();
    }
}	

这里设置了sun.misc.ProxyGenerator.saveGeneratedFiles为true,我们可以在 根目录下查看生成的字节码文件。 在这里插入图片描述

package com.sun.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import jdkProxy.ParentInterface;

public final class $Proxy0 extends Proxy implements ParentInterface {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    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})).booleanValue();
        } 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 void doSome() throws  {
        try {
            super.h.invoke(this, m3, (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)).intValue();
        } 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("jdkProxy.ParentInterface").getMethod("doSome");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

工作流程:

1、在代理类中调用 java.lang.reflect.Proxy 的 newProxyInstance 方法,创建字节码文件;

参数为:目标对象的类加载器,目标对象的所有接口,当前代理类实例this。

2、使用ClassLoader将字节码文件加载到JVM;

3、创建动态代理实例对象,并返回;

4、调用动态代理实例的方法;

5、动态代理实例调用代理类的invoke方法;该方法中调用了目标类的方法和增强方法。

CGLib

采用底层的字节码技术,全称 code generation libarary 。创建一个子类,实现需要代理的类;在子类中采用拦截方法,拦截父类方法,并织入横切代码。

public class TargetInterceptor implements MethodInterceptor {
    /**

     - Cglib 动态代理的处理方法

     - */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

        // 方法调用返回值
        Object result = null;
        System.out.println("方法开始");
        result = methodProxy.invokeSuper(o,objects);
        System.out.println("方法结束");

        return result;
    }

    public CglibTarget getProxy(){
        // Enhancer 为 Cglib中的字节码增强器,将目标类和动态处理类传入此增强器,调用增强器的create方法返回代理对象
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(CglibTarget.class);
        enhancer.setCallback(this);
        return (CglibTarget)enhancer.create();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值