java静态代理和JDK、CGLIB动态代理

一、参考

  1. JAVA动态代理详解
  2. 什么是Java动态代理?
  3. 探究动态代理与CGLIB的奥秘:Java代理模式的两种实现方式

二、代理

代理模式是常用的Java 设计模式,它的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。

在这里插入图片描述
重要的三个对象:

  • 真实实现
  • 代理对象(增强处理)
  • 接口(代理和真实实现要有相同的接口)

为什么需要动态代理?

动态代理最大的优势在于“解耦”,即不用更改原始业务代码,就能实现不同的功能。

动态代理的常见应用场景包括:

  • 日志记录:在方法调用前后记录日志。
  • 性能监控:在方法执行前后记录时间以计算执行效率。
  • 事务管理:自动处理事务的开启和关闭。
  • 权限控制:在方法执行前检查用户权限。

三、代理实现

3.1 静态代理

3.1 什么是静态代理

静态代理要求我们提前定义代理类

3.2 静态代理案例

在这里插入图片描述

package com.hb.proxy.jingtai;

public interface Service {
    void execute();
}

package com.hb.proxy.jingtai;

public class RealService implements Service {
    public void execute() {
        System.out.println("执行实际服务逻辑");
    }
}

package com.hb.proxy.jingtai;

public class StaticProxy implements Service {
    private Service realService;
    public StaticProxy(Service realService) {
        this.realService = realService;
    }

    @Override
    public void execute() {
        System.out.println("执行前的操作...");
        realService.execute();
        System.out.println("执行后的操作...");
    }
}
package com.hb.proxy.jingtai;

public class StaticProxyDemo {
    public static void main(String[] args) {
        Service realService = new RealService();
        Service proxy = new StaticProxy(realService);
        proxy.execute();
    }
}

3.2 JDK 实现动态代理

3.2.1 JDK 实现动态代理原理

JDK的动态代理机制只能代理实现了接口的类,在程序运行时,运用反射机制动态创建代理实例对象。

3.2.2 JDK 实现动态代理例子

在这里插入图片描述

  1. 定义接口
package com.hb.proxy.dongtai.jdk;

public interface User {
    void eat();
    void run();
}
  1. 定义接口实现的类(需要被代理的对象)
package com.hb.proxy.dongtai.jdk;

public class RealUser implements User {
    public void eat() {
        System.out.println("执行实际 eat 服务逻辑");
    }

    public void run() {
        System.out.println("执行实际 run 服务逻辑");
    }
}
  1. 定义代理增强,需要实现 InvocationHandler 接口
package com.hb.proxy.dongtai.jdk;

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

public class DynamicProxyHandler implements InvocationHandler {

    private Object target;

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("执行前的操作...");
        Object result = method.invoke(target, args);
        System.out.println("执行后的操作...");
        return result;
    }
}
  1. 测试验证jdk 动态代理
package com.hb.proxy.dongtai.jdk;

import java.lang.reflect.Proxy;

public class DynamicProxyDemo {

    public static void main(String[] args) {
        User realService = new RealUser();
        User proxy = (User) Proxy.newProxyInstance(
                realService.getClass().getClassLoader(),
                realService.getClass().getInterfaces(),
                new DynamicProxyHandler(realService)
        );
        proxy.run();
        proxy.eat();
    }
}

3.3 CGLIB 实现动态代理

3.3.1 CGLIB 实现动态代理的原理(子类继承)

cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理

3.3.2 CGLIB 实现动态代理例子

在这里插入图片描述

  1. pom.xml 引入依赖文件
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.1</version>
</dependency>
  1. 定义被代理的类
package com.hb.proxy.dongtai.cglib;
 public class BookFacadeImpl1 {
    public void addBook() {
        System.out.println("增加图书的普通方法...");
    }
}

  1. 定义增强类,需要实现MethodInterceptor 接口
package com.hb.proxy.dongtai.cglib;

import java.lang.reflect.Method;

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

public class BookFacadeCglib implements MethodInterceptor {
    private Object target;

    /**
     * 创建代理对象
     *
     * @param target
     * @return
     */
    public Object getInstance(Object target) {
        this.target = target;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(this.target.getClass());
        // 回调方法
        enhancer.setCallback(this);
        // 创建代理对象
        return enhancer.create();
    }

    @Override
    // 回调方法
    public Object intercept(Object obj, Method method, Object[] args,
                            MethodProxy proxy) throws Throwable {
        System.out.println("事物开始");
        proxy.invokeSuper(obj, args);
        System.out.println("事物结束");
        return null;
    }
}
  1. 测试类,验证 cglib 代理
package com.hb.proxy.dongtai.cglib;

public class TestCglib {
    public static void main(String[] args) {
        BookFacadeCglib cglib = new BookFacadeCglib();
        BookFacadeImpl1 bookCglib = (BookFacadeImpl1) cglib.getInstance(new BookFacadeImpl1());
        bookCglib.addBook();
    }
}

JDK动态代理与CGLIB代理的区别

  • 接口 vs. 类: 动态代理要求被代理对象实现一个接口,而CGLIB代理可以代理普通类。

  • 性能: 通常情况下,动态代理的性能较差,因为它需要使用反射机制,而CGLIB代理通过生成子类来调用方法,性能更高。

JDK 1.8 对反射做了优化,现在CGLIB 与 JDK 性能几乎一样,没有太大的区别

  • 使用场景: 如果被代理对象已经实现了接口,或者你需要代理的是一个接口,那么动态代理是一个合适的选择。如果被代理对象是一个普通类,或者你无法修改被代理对象的源代码,那么CGLIB代理可能更适合。

  • 依赖库: 动态代理是Java的标准库的一部分,无需额外的依赖。CGLIB代理需要引入CGLIB库。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值