Java代理模式:静态代理、动态代理和cglib代理

内容纲要

概述

代理模式为另一个对象提供一个替身或占位符以控制对这个对象的访问。
使用代理模式代表对象,让代表对象控制某个对象的访问或者增强某个对象的功能。

代理模式图

Java三种主要的代理方式:

  1. 静态代理
  2. 动态代理
  3. cglib代理

三种方式对比

  1. 静态代理:
    静态代理是通过手动编写代理类来实现的。在静态代理中,代理类和目标类实现相同的接口,代理类持有目标类的引用,并在方法调用前后进行额外的处理。静态代理的优点是简单易懂,但缺点是需要为每个目标类编写一个代理类,导致代码冗余。

  2. 动态代理:
    动态代理是在运行时动态生成代理类的方式。Java提供了java.lang.reflect包来支持动态代理。在动态代理中,代理类不需要手动编写,而是通过使用Proxy类和InvocationHandler接口来实现。通过动态代理,可以在运行时为多个目标类生成代理对象,并在方法调用前后进行额外的处理。动态代理的优点是可以减少代码冗余,但缺点是相对复杂一些。

  3. CGLIB代理:
    CGLIB(Code Generation Library)是一个强大的第三方库,用于在运行时生成Java字节码。CGLIB代理不需要目标类实现接口,它通过继承目标类并重写其中的方法来实现代理。CGLIB代理的优点是可以代理没有实现接口的类,但缺点是生成的代理类会比较庞大,且对final方法和private方法无法进行代理。
    这三种代理方式各有优缺点,可以根据具体的需求和场景选择适合的代理方式。静态代理适用于目标类较少且固定的情况,动态代理适用于目标类较多且需要动态生成代理的情况,而CGLIB代理适用于无法实现接口的类的代理。

代码实现-静态代理

Java 代码


// 接口定义
public interface Interface {

    void doSomething();

    void somethingElse(String arg);
}

// 接口实现
public class RealObject implements Interface {
    @Override
    public void doSomething() {
        System.out.println("doSomething.");
    }

    @Override
    public void somethingElse(String arg) {
        System.out.println("doSomethingElse " + arg);
    }
}

// 代理类
public class SimpleProxy implements Interface {

    private Interface proxied;

    public SimpleProxy(Interface proxied) {
        this.proxied = proxied;
    }

    @Override
    public void doSomething() {
        System.out.println("SimpleProxy doSomething.");
        proxied.doSomething();
    }

    @Override
    public void somethingElse(String arg) {
        System.out.println("SimpleProxy somethingELse " +  arg);
        proxied.somethingElse(arg);
    }
}

// 测试客户端
public class SimpleProxyDemo {

    static void consumer(Interface iface) {
        iface.doSomething();
        iface.somethingElse("bonobo");
    }

    public static void main(String[] args) {
        consumer(new RealObject());

        consumer(new SimpleProxy(new RealObject()));
    }
}

代码实现-动态代理

动态代理实现

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

public class DynamicProxyHandler implements InvocationHandler {
    private Object proxied;

    public DynamicProxyHandler(Object proxied) {
        this.proxied = proxied;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("*** proxy: " + proxied.getClass() + ", method: " + method);
        return method.invoke(proxied, args);
    }
}

测试类

import helper.proxy.common.Interface;
import helper.proxy.common.RealObject;

import java.lang.reflect.Proxy;

public class SimpleDynamicProxy {

    static void consumer(Interface iface) {
        iface.doSomething();
        iface.somethingElse("bonobo");
    }

    public static void main(String[] args) {
        RealObject real = new RealObject();
        consumer(real);

        System.out.println("===========================================================");

        Interface proxy = (Interface) Proxy.newProxyInstance(Interface.class.getClassLoader(),
                new Class[] {Interface.class},
                new DynamicProxyHandler(real));
        consumer(proxy);
    }
}

cglib代理

介绍

代码实现

maven依赖引入

<dependency>
  <groupId>cglib</groupId>
  <artifactId>cglib</artifactId>
  <version>3.2.5</version>
</dependency>

<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.12</version>
  <scope>test</scope>
</dependency>

代码实现

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

import java.lang.reflect.Method;

public class TransactionHandler implements MethodInterceptor {

    private Object proxied;

    public TransactionHandler(Object proxied) {
        this.proxied = proxied;
    }

    public Object getProxyInstance() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(proxied.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("开启事务");
        Object ret = method.invoke(proxied, objects);
        System.out.println("提交事务");
        return ret;
    }
}

测试用例

import org.junit.Test;

public class TransactionHandlerTest {

    @Test
    public void testNormal() {
        Interface realObject = new RealObject();
        TransactionHandler transactionHandler = new TransactionHandler(realObject);
        Interface proxied = (Interface) transactionHandler.getProxyInstance();
        proxied.doSomething();
        proxied.somethingElse("cglib");
    }
}

用例输出

7bf86471294f0c1c11bfdd966240d4ee.png

参考

  1. Java编程思想
  2. https://segmentfault.com/a/1190000011291179
  3. https://www.liaoxuefeng.com/wiki/1252599548343744/1264804593397984

发表评论

您的电子邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部