0
点赞
收藏
分享

微信扫一扫

服务器禁止ping

眼君 2023-12-03 阅读 39

代理模式

分类/JavaEE/代理1.png  0 → 100644

代理模式又分为两大类:静态代理和动态代理。其中动态代理又分为JDK代理和CGLIB代理。

1. 静态代理

1.1实现方式

代理类与委托类实现同一接口。在代理类中需要硬编码接口。

1.2 优点

实现简单,容易理解。

1.3 缺点

代理类需要硬编码接口,在实际应用中可能会导致重复编码,浪费存储空间并且效率较低。

1.4 实现代码
package com.wnhz.smart.order.proxy.sta;

/**
 * @author Hao
 * @date 2023-11-28 20:10
 */
public class StaticProxyDemo {
    public static void main(String[] args) {
        // 被代理对象
        RealObject realObject = new RealObject();
        // 创建代理对象
        StaticProxy proxy = new StaticProxy(realObject);
        // 实现静态代理,调用代理对象的方法
        proxy.doSomething();
    }
}

interface MyInterface {
    void doSomething();
}

class RealObject implements MyInterface {
    @Override
    public void doSomething() {
        System.out.println("RealObject doSomething");
    }
}

class StaticProxy implements MyInterface {
    private RealObject realObject;

    public StaticProxy(RealObject realObject) {
        this.realObject = realObject;
    }

    @Override
    public void doSomething() {
        System.out.println("Before method invocation");
        realObject.doSomething();
        System.out.println("After method invocation");

    }
}

2. JDK动态代理

2.1实现方式

代理类与委托类实现同一接口。代理类要实现 InvocationHandler 接口并重写 invoke 方法。invoke 方法中可以对委托方法进行增强处理。

2.2 优点

不需要硬编码接口,代码复用率高。

2.3 缺点

只能够代理实现了接口的委托类。

2.4 特点

底层使用反射机制进行方法的调用。

2.5 实现代码
package com.proxy.jdk;

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

/**
 * @author Hao
 * @date 2023-11-28 19:34
 */
public class JDKProxyDemo {
    public static void main(String[] args) {
        RealObject real = new RealObject();
        InvocationHandler handler = new DynamicProxy(real);
        // 创建代理对象
        MyInterface proxy = (MyInterface) Proxy.newProxyInstance(
                MyInterface.class.getClassLoader(),
                new Class<?>[]{MyInterface.class},
                handler);
        // 调用代理对象的方法
        proxy.doSomething();
    }
}

interface MyInterface {
    void doSomething();
}

class RealObject implements MyInterface {
    @Override
    public void doSomething() {
        System.out.println("RealObject doSomething");
    }
}

class DynamicProxy implements InvocationHandler {
    private Object target;

    public DynamicProxy(Object target) {
        this.target = target;
    }

    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        System.out.println("Before method invocation");
        Object result = method.invoke(target, args);
        System.out.println("After method invocation");
        return result;
    }
}

结果:

2.6 总结

JDK动态代理只能代理接口实现类,原因是JDK动态代理是基于接口实现的,代理对象的类型由接口列表决定。如果你想代理一个类而不是一个接口,你需要使用其他的代理技术,比如CGLIB动态代理。

CGLIB 动态代理

3.1实现方式

代理类将委托类作为自己的父类并为其中的非 final 委托方法创建两个方法,一个是与委托方法签名相同的方法,它在方法中会通过 super 调用委托方法;另一个是代理类独有的方法。在代理方法中,它会判断是否存在实现了MethodInterceptor 接口的对象,若存在则将调用 intercept 方法对委托方法进行代理。

3.2 优点

可以在运行时对类或者是接口进行增强操作,且委托类无需实现接口。

3.3 缺点

不能对 final 类以及 final 方法进行代理。

3.4 特点

底层将方法全部存入一个数组中,通过数组索引直接进行方法调用。

3.5 代码实现
package com.proxy.cglib;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * @author Hao
 * @date 2023-11-28 19:58
 */
public class CGLIBProxyDemo {
    public static void main(String[] args) {
        RealObject real = new RealObject();
        MethodInterceptor handler = new CGLIBProxy(real);
        // 创建代理对象
        RealObject proxy = (RealObject) Enhancer.create(
                RealObject.class,
                handler);
        // 调用代理对象的方法
        proxy.doSomething();
    }
}

class RealObject {
    public void doSomething() {
        System.out.println("RealObject doSomething");
    }
}

class CGLIBProxy implements MethodInterceptor {
    private Object target;

    public CGLIBProxy(Object target) {
        this.target = target;
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("Before method invocation");
        Object result = proxy.invoke(target, args);
        System.out.println("After method invocation");
        return result;
    }
}

结果:

两者之间的优缺点

JDK动态代理的优点:
  • JDK动态代理是Java标准库的一部分,因此它不需要引入任何外部依赖。

  • JDK动态代理只需要实现接口即可生成代理对象,不需要改变原有类的结构。

  • 由于JDK动态代理是基于接口实现的,因此它更适合用于代理接口实现类的场景。

JDK动态代理的缺点:
  • JDK动态代理只能代理实现了接口的类,无法代理没有实现接口的类。

  • JDK动态代理在生成代理对象时,需要使用反射机制,因此它的效率相对较低。

CGLIB代理的优点:
  • CGLIB代理是基于字节码技术实现的,因此它的效率比JDK动态代理更高。

  • CGLIB代理可以代理没有实现接口的类。

CGLIB代理的缺点:
  • CGLIB代理需要引入外部依赖。

  • CGLIB代理在生成代理对象时,需要改变原有类的结构,因此它可能会引起一些问题,例如无法代理final类或final方法等问题。

举报

相关推荐

0 条评论