Java静态代理和动态代理

Java静态代理和动态代理

静态代理

package com.liuliu.spring.service;

/**
 * 静态代理的实现步骤描述:
 *
 * 定义目标接口:创建一个接口,包含需要被代理的方法。
 *
 * 实现真实对象:实现该接口的具体类,包含实际的业务逻辑。
 *
 * 创建代理类:创建一个代理类,同样实现目标接口,持有对真实对象的引用,并在方法中添加额外的逻辑。
 *
 * 使用代理类:在主程序中,实例化真实对象和代理对象,通过代理对象调用方法,从而实现对真实对象方法的增强。
 */
public class StaticProxy {
    public static void main(String[] args) {
        MyService3 realService = new MyServiceImpl3();
        MyService3 proxyService = new MyServiceProxy(realService);

        // 调用代理方法
        int result = proxyService.performAction(5);
        System.out.println("Result: " + result);
    }
}

// 抽象主题(Subject)接口
interface MyService3 {
    int performAction(int value);
}


// 真实主题(Real Subject)
class MyServiceImpl3 implements MyService3 {
    @Override
    public int performAction(int value) {
        System.out.println("Action performed with value: " + value);
        return value * 3; // 示例:返回值为参数的两倍
    }
}


// 代理类
class MyServiceProxy implements MyService3 {

    // 抽象主题接口的引用
    private final MyService3 realService;

    public MyServiceProxy(MyService3 realService) {
        this.realService = realService;
    }

    @Override
    public int performAction(int value) {
        System.out.println("Before method call");

        // 调用真实主题的方法并获取返回值
        int result = realService.performAction(value);

        System.out.println("After method call");

        // 返回结果
        return result;
    }
}

JDK动态代理

package com.liuliu.spring.service;

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


/**
 * 具体实现
 * 代理模式涉及以下几个角色:
 * <p>
 * 抽象主题(Subject):是一个接口或抽象类,定义了真实主题和代理对象共同实现的方法,客户端通过抽象主题访问真实主题。
 * 真实主题(Real Subject):是真正执行业务逻辑的对象,实现了抽象主题定义的方法,是代理模式中被代理的对象。
 * 代理(Proxy):持有对真实主题的引用,可以控制对真实主题的访问,在其自身的方法中可以调用真实主题的方法,同时也可以在调用前后执行一些附加操作。
 * ————————————————
 *
 * JDK 动态代理的实现步骤主要包括以下几个步骤:
 *     引入 JDK 动态代理支持:确保你的项目中使用 Java 反射机制。
 *     定义接口:创建一个接口,包含要代理的方法。
 *     实现真实类:创建一个实现上述接口的真实类,定义具体的业务逻辑。
 *     实现 InvocationHandler:通过实现 InvocationHandler 接口来定义增强逻辑,重写 invoke() 方法。
 *     创建代理实例:使用 Proxy 类的 newProxyInstance() 方法,指定类加载器、接口和 InvocationHandler 实现,创建代理对象
 */

public class JDKProxy {
    public static void main(String[] args) {
        MyService realService = new MyServiceImpl();

        // 创建代理实例
        MyService proxyService = (MyService) Proxy.newProxyInstance(
                MyService.class.getClassLoader(),  // 类的加载器
                new Class<?>[]{MyService.class}, // 抽象主题接口
                new MyInvocationHandler(realService) // 真实主题
        );

        // 调用代理方法
        int result = proxyService.performAction(5);
        System.out.println("Result: " + result);
    }
}


// 抽象主题(Subject)接口
interface MyService {
    int performAction(int value);
}

// 真实主题(Real Subject)
class MyServiceImpl implements MyService {
    @Override
    public int performAction(int value) {
        System.out.println("Action performed with value: " + value);
        return value * 2; // 示例:返回值为参数的两倍
    }
}


// 代理(Proxy)
class MyInvocationHandler implements InvocationHandler {
	/**
     * 表示真实被代理的对象 MyServiceImpl 
     */
    private final Object target;

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

    /**
     * @param proxy  就是调用该方法的对象(由Proxy.newProxyInstance返回的代理实例)
     * @param method 相当于被代理类的方法:比如performAction(int value)
     * @param args   被代理类方法传递的参数:比如performAction(5)
     * @return 一般返回方法的返回值,如果返回null,就空指针异常??
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before method call");

        // 调用真实主题的方法并获取返回值
        Object result = method.invoke(target, args);

        System.out.println("After method call");

        // 返回方法的返回值
        return result;
    }
}

Cglib动态代理

package com.liuliu.spring.service;

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

/**
 * CGLIB 动态代理的实现过程主要包括以下几个步骤:
 * <p>
 * 引入 CGLIB:确保你在项目中添加了 CGLIB 的依赖。
 * 定义真实类:创建要代理的真实类。(不需要抽象类)
 * 实现 MethodInterceptor:通过实现 MethodInterceptor 接口来定义增强逻辑(通过重写方法intercept())。
 * 使用 Enhancer 创建代理:通过 Enhancer 类设置父类和回调,然后创建代理实例。
 */

public class CglibProxy {
    public static void main(String[] args) {
        // 创建 Enhancer 对象
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(MyServiceImpl2.class); // 设置父类为 MyServiceImpl2
        enhancer.setCallback(new MyMethodInterceptor()); // 设置方法拦截器

        // 创建代理实例
        MyServiceImpl2 proxyService = (MyServiceImpl2) enhancer.create();

        // 调用代理方法
        int result = proxyService.performAction(5);
        System.out.println("Result: " + result);
    }
}

// 真实主题(Real Subject)
class MyServiceImpl2 {
    public int performAction(int value) {
        System.out.println("Action performed with value: " + value);
        return value * 2; // 示例:返回值为参数的两倍
    }
}

// 代理(Proxy)
class MyMethodInterceptor implements MethodInterceptor {
    /**
     * @param obj    传入的是代理实例 proxyService,即 MyServiceImpl2。
     * @param method 传入的是被调用的 performAction 方法的 Method 对象。
     * @param args   传入的是调用 performAction 时提供的参数数组,这里是一个包含值 5 的数组,即 new Object[]{5}。
     * @param proxy  传入的是 CGLIB 的 MethodProxy 对象,用于调用真实的 performAction 方法。
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("Before method call");

        // 调用真实主题的方法并获取返回值
        Object result = proxy.invokeSuper(obj, args);

        System.out.println("After method call");

        // 返回方法的返回值
        return result;
    }
}


静态代理、JDK动态代理和CGLIB动态代理的区别

特性静态代理JDK动态代理CGLIB动态代理
定义编译时生成代理类运行时通过反射生成代理类运行时通过字节码生成代理类
实现方式手动实现代理接口依赖Java接口通过继承被代理类
优点简单直观,易于理解代码量少,灵活性高可以代理没有接口的类,性能较好
缺点增加代码量,维护复杂只能代理实现接口的类不能代理final类或final方法
性能较好较低(因使用反射)较好
适用场景简单或固定的代理需求大部分动态代理情境需要代理没有接口的类或所有方法

选择建议

  • 实现接口:选择JDK动态代理。
  • 无接口:选择CGLIB动态代理。
  • 简单需求:考虑静态代理。

Spirng中的动态代理的场景:

  • Spring AOP 默认使用 JDK 动态代理,如果被代理的类实现了接口。

  • 如果目标类没有实现任何接口,或者你强制要求使用 CGLIB 代理,可以通过配置来指定。

    <aop:aspectj-autoproxy proxy-target-class="true" />
    

参考来源:一文搞懂设计模式—代理模式_软件设计模式proxy模式-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值