简单聊聊静态代理与动态代理(JDK动态代理与CGLIB)

静态代理与动态代理(JDK动态代理与CGLIB)

代理

代理是什么?我们来看一下百度百科:
在这里插入图片描述
由此我们可以联想到我们在java中使用的代理,当我们在操作一个对象的时候,我们不想更改这个对象或者无法直接操作这个对象时,我们就需要一个代理对象来进行操作。就想现实中的代购,代驾等。
java中代理模式又分为静态代理和动态代理。下面我就简单介绍一下:

静态代理

静态代理在程序运行前已经编译好的代理类,可以通过程序员手打或者使用工具生成。下面是一个简单的静态代理实现:

interface Hello{
    String sayHello(String hero);
}

class  HelloImpl implements Hello{
    @Override
    public String sayHello(String hero) {
        return "HelloImp"+str;
    }
}
/**
 * 静态代理
 */
class StaticProxyHello implements Hello{

    private Hello hello = new HelloImpl();

    @Override
    public String sayHello(String hero) {
        return hello.sayHello(hero);
    }
}

动态代理

当我们程序涉及使用到大量的代理类时,单纯的手打或工具类生成不仅会耗费大量的时间,而且会造成大量的代码冗余。使用动态代理,不仅可以实现原先类方法的功能,而且还在原来的基础上添加了额外的功能。由于代理类是动态生成的,即具有解耦意义,灵活并且扩展性强。我们经常使用的SpringAOP, RPC等都使用了动态代理。下面就使用简单的代码来模拟一下两种不同的动态代理实现:

JDK动态代理

java内置的,是基于接口来实现代理的,通过接口继承java.lang.reflect包下的InvocationHandler接口,底层通过反射实现代理。
主要方法:
Proxy.newProxyInstance(getClass().getClassLoader(),
new Class[]{Hello.class},
new LogInvocationHandler(new HelloImpl()));
传入代理对象的类加载器,代理对象需要实现的接口,方法调用的实际处理者 三个参数来返回一个代理对象。这个代理对象包括被代理对象的所有方法,还包括在invoke中对原对象进行扩展、修改的方法。

/**
 * JDK动态代理
 */
class LogInvocationHandler implements InvocationHandler{

    private Object hello;

    public LogInvocationHandler(Object hello) {
        this.hello = hello;
    }

    public LogInvocationHandler() {

    }

    public Object CreateHelloProxy(){

       hello  = (Hello) Proxy.newProxyInstance(getClass().getClassLoader(),new Class[]{Hello.class},new LogInvocationHandler(new HelloImpl()));
        return hello;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if("sayHello".equals(method.getName())){
            System.out.println("进入代理,可随意操作");
        }
        return method.invoke(hello,args);
    }
}

测试类

public class MyTest {

    public static void main(String[] args) {
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"D:\\CODEGENERATION");
        LogInvocationHandler logInvocationHandler = new LogInvocationHandler();
        Hello o = (Hello)logInvocationHandler.CreateHelloProxy();
        String s = o.sayHello("你好吗?杰克");
        System.out.println(s);
    }

}

CGLIB代理

CGLIB(Code Generation Library ):是基于ASM的字节码生成库,通过继承MethodInterceptor实现代理,底层提供了FastClass增强功能,主要是用于调用方法时变量的场景,用于替代反射调用

public class CGLIBLogInvationHanlder implements MethodInterceptor{

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("进入CGLIB代理类");
        return methodProxy.invokeSuper(o,objects);
    }
}

class HelleCGLIB{
    public String sayHello(String str){
        return "HelloCGLIB"+str;
    }
}

测试类

public class MyTest {

    public static void main(String[] args) {
        
       System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"D:\\CODEGENERATION");
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(HelleCGLIB.class);
        enhancer.setCallback(new CGLIBLogInvationHanlder());
        HelleCGLIB helleCGLIB = (HelleCGLIB) enhancer.create();
        String cglib = helleCGLIB.sayHello("我是CGLIB");
        System.out.println(cglib);

    }
    
}

FastClass机制:
首先,我们创建EnHancer对象,然后通过setSuperClass()设置需要代理的对象,再用setCallback()设置回调函数,也就是你实现MethodInterceptor接口的类,之后用create()创建出代理对象A。当使用A调用sayHello()方法时,首先进入intercept方法,然后进入methodProxy.invokeSuper(o,object)
在这里插入图片描述
这里我们可以看到传入的参数是代理对象与Object数组,
然后通过init()
在这里插入图片描述
也就是,在我们使用A调用sayHello()方法时,在代理类中会进行判断是否实现了MethodInterceptor,如果没有,则直接调用A的sayHello();如果实现了MethodInterceptor,在MethodInterceptor中会为A中的所有方法建立索引,建立索引底层在FastClass中将每个方法的引用保存在数组中,这样当调用方法时就可以直接通过索引来调用,而不使用反射;这里只有一个方法,可以看到传入的args为Object[1]。
在这里插入图片描述
日拱一卒,得寸进尺。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值