java 三种代理模式

本文介绍了代理模式,包括静态代理、JDK动态代理和CGLIB动态代理。静态代理在编译期确定代理对象,可扩展目标对象功能,但有重复工作。JDK动态代理中代理类无需实现接口,目标类需实现接口。CGLIB代理通过构建子类对象扩展功能,代理类不能为final。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

代理(Proxy)是一种设计模式,定义:为其他对象提供一个代理以控制对某个对象的访问,即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.
  这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法
示例代码: https://github.com/steveNash12/microservice/tree/master/microservice/proxy

静态代理

在编译期确定代理对象。静态代理在使用是时,需要定义接口类,并且被代理的对象和代理类需要一起实现接口类。
例子:
接口类

public interface Subject {

    public void play();

    public void sayHi();
}

被代理的类(真实业务类)

public class RealSubject implements Subject {
    @Override
    public void play() {
        System.out.println("this is RealSubject");
    }

    @Override
    public void sayHi() {
        System.out.println("hello, everyone this is RealSubject");
    }
}

代理类

package xyz.songxl.staticp;

import xyz.songxl.pattern.RealSubject;
import xyz.songxl.pattern.Subject;

/**
 * @author songxl
 * @create 2019-07-10 15:17
 * @desc 静态代理  代理类和正式的业务类需要实现同一个接口
 **/
public class StaticProxy implements Subject {

    private RealSubject realSubject;
    public StaticProxy(RealSubject realSubject) {
        this.realSubject = realSubject;
    }
    @Override
    public void play() {
        System.out.println("this is proxy");
        try {
            realSubject.play();
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
    }

    @Override
    public void sayHi() {
        System.out.println("this is proxy");
        try {
            realSubject.sayHi();
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
    }
}

测试类:

 public static void main(String[] args) {

        Subject staticProxy = new StaticProxy(new RealSubject());
        // 执行代理方法
        staticProxy.play();
        staticProxy.sayHi();

    }

静态代理总结:
1. 优点 : 可以做到在不修改目标对象的情况下,对目标对象进行功能扩展
2. 缺点:每个需要代理的方法都需要手动去写代理方法 对于方法比较多的情况下,会有很多的重复工作

动态代理(jdk 动态代理)

由于上面静态代理工作量重复的问题,动态代理应运而生。
动态代理通过反射机制实现

例子:
业务类继续使用上面的 RealSubject.java
代理类

package xyz.songxl.dynamic;

import xyz.songxl.pattern.RealSubject;

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

/**
 * @author songxl
 * @create 2019-07-10 15:34
 * @desc jdk 动态代理
 **/
public class JdkProxySubject implements InvocationHandler {

    private RealSubject realSubject;
    public JdkProxySubject(RealSubject realSubject) {
        this.realSubject = realSubject;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("dynamic JdkProxySubject");
        Object result = null;
        try {
            // 通过反射 找到调用的方法
            result = method.invoke(realSubject,args);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } finally {
            System.out.println("after ");
        }

        return result;
    }
}

测试类
 Subject jdkProxy = (Subject) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),new Class[]{Subject.class},new JdkProxySubject(new RealSubject()));
        jdkProxy.play();
        jdkProxy.sayHi();

jdk 动态代理总结:
代理类不需要实现接口,但是目标类一定要实现接口,否则不能使用动态代理

CGLIB 动态代理

例子:

package xyz.songxl.cglib;



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

import java.lang.reflect.Method;

/**
 * @author songxl
 * @create 2019-07-10 17:13
 * @desc cglib 动态代理模式
 **/
public class CglibProxySubject implements MethodInterceptor {

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("CglibProxySubject");
        Object result = null;
        try {
            result = methodProxy.invokeSuper(o,objects);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return result;
    }
}

测试类

 // cglib 动态代理
        Enhancer enhancer = new Enhancer();
        // 设置真实的业务类
        enhancer.setSuperclass(RealSubject.class);
        // 需要置入的代码类(代理类)
        enhancer.setCallback(new CglibProxySubject());
        // 创建代理实例
        Subject cglibProxy = (Subject) enhancer.create();
        cglibProxy.sayHi();

cglib代理总结:
Cglib代理,也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展.
代理的类不能为final,否则报错;目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法.

总结

代理方式实现优点缺点特点
静态代理需要定义接口类,并且被代理的对象和代理类需要一起实现接口类实现简单每个需要代理的方法都需要手动去写代理方法 对于方法比较多的情况下,会有很多的重复工作可扩展目标对象功能
jdk动态代理代理类需要实现InvocationHandler 接口并重写invoke方法不需要为每一个需要代理的方法实现代理方法,代码复用率高只能代理有实现了接口的代理反射
cglib 动态代理代理类实现MethodInterceptor接口 并重写intercept方法不需要为每一个需要代理的方法实现代理方法,代码复用率高 。也可以对代理对象进行扩展,代理对象不用实现接口不能对static final 类、private static 方法进行代理通过 节码处理框架ASM来转换字节码并生成新的子类来实现代理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值