什么是动态代理简单易懂

1.什么是动态代理

动态代理是一种在程序运行时(而非编译时)动态生成代理对象的技术。代理对象可以拦截对目标对象的方法调用,并在调用前后执行一些自定义逻辑

2.动态代理的作用和应用场景
  • 面向切面编程(AOP):动态代理可以实现横切关注点,比如日志记录、权限检查、事务管理等,而不需要侵入到业务代码中。
  • 权限控制:通过动态代理,可以在调用业务方法前后检查用户是否有权限执行某些操作。
  • 事务管理:拦截业务方法,在其调用前后进行事务的开启和提交。
  • 日志记录:在方法调用前后自动记录日志。
3.动态代理几种形式
3.1 JDK动态代理
  • 简介: JDK 动态代理是 Java 内置的一种代理机制,它适用于代理接口实现类,也就是说目标对象必须实现一个或多个接口。
  • 实现方式: 使用 java.lang.reflect.Proxy 类和 InvocationHandler 接口来实现动态代理。
  • 优点: 简单易用,直接支持接口代理,适用于大多数场景。
  • 缺点: 只能代理实现了接口的类,无法代理普通的类。

案例:

接口

public interface UserService {
    void addUser(String username);
}

实现类

public class UserServiceImpl implements UserService {
    @Override
    public void addUser(String username) {
        System.out.println("Adding user: " + username);
    }
}

代理实现

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

public class UserServiceProxy {
    public static void main(String[] args) {
        UserService target = new UserServiceImpl();

        // 创建代理对象
        UserService proxy = (UserService) Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    System.out.println("Before method: " + method.getName());
                    Object result = method.invoke(target, args); // 调用目标对象的方法
                    System.out.println("After method: " + method.getName());
                    return result;
                }
            }
        );

        // 使用代理对象调用方法
        proxy.addUser("Tom");
    }
}

运行结果

3.2 CGLIB 动态代理
  • 简介: CGLIB (Code Generation Library) 是一个第三方库,可以动态生成字节码来创建代理对象。与 JDK 动态代理不同,CGLIB 可以代理普通类(非接口)
  • 实现方式: 通过继承目标类并重写方法实现代理,这也是为什么 CGLIB 不能代理 final 类或 final 方法。
  • 优点: 可以代理没有实现接口的类,性能通常比 JDK 代理快。
  • 缺点: 需要额外的库(CGLIB),不能代理 final 类或方法。

案例:

引入maven坐标:

普通类

public class UserService {
    public void addUser(String username) {
        System.out.println("Adding user: " + username);
    }
}

代理实现

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

public class CglibProxyExample implements MethodInterceptor {
    private Object target;

    public Object getProxyInstance(Object target) {
        this.target = target;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(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("Before method: " + method.getName());
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("After method: " + method.getName());
        return result;
    }

    public static void main(String[] args) {
        UserService userService = new UserService();
        UserService proxy = (UserService) new CglibProxyExample().getProxyInstance(userService);
        proxy.addUser("Tom");
    }
}

运行结果

 3.3 Javassist 动态代理
  • 简介: Javassist 是一个操作字节码的库,可以在运行时动态生成和修改 Java 字节码。相比 CGLIB 和 JDK 动态代理,Javassist 更灵活,可以直接操作类和方法。
  • 实现方式: 通过 javassist.util.proxy 包或者直接操作字节码来创建代理类。
  • 优点: 可以直接修改类的字节码,灵活性更高。
  • 缺点: 使用复杂,需要熟悉字节码操作。

引入maven坐标

import javassist.util.proxy.MethodHandler;
import javassist.util.proxy.ProxyFactory;
import javassist.util.proxy.ProxyObject;

public class JavassistProxyExample {
    public static void main(String[] args) throws Exception {
        // 创建代理工厂
        ProxyFactory factory = new ProxyFactory();
        factory.setSuperclass(UserService.class);

        // 设置方法拦截器
        MethodHandler handler = (self, thisMethod, proceed, args1) -> {
            System.out.println("Before method: " + thisMethod.getName());
            Object result = proceed.invoke(self, args1); // 调用原始方法
            System.out.println("After method: " + thisMethod.getName());
            return result;
        };

        // 生成代理对象
        Class<?> proxyClass = factory.createClass();
        UserService proxy = (UserService) proxyClass.getDeclaredConstructor().newInstance();
        ((ProxyObject) proxy).setHandler(handler);

        // 使用代理对象
        proxy.addUser("Tom");
    }
}

class UserService {
    public void addUser(String name) {
        System.out.println("Adding user: " + name);
    }
}

运行结果

3.4 ByteBuddy 动态代理
  • 简介: ByteBuddy 是一个更现代的字节码操作库,设计上比 Javassist 更加友好和灵活,可以非常方便地创建和操作代理对象。
  • 实现方式: 使用 ByteBuddy 类库,可以轻松创建和操作类。
  • 优点: 语法友好,适合动态生成和操作复杂类,支持创建代理类。
  • 缺点: 学习曲线较高,需要引入第三方库。

引入maven坐标

import javassist.util.proxy.MethodHandler;
import javassist.util.proxy.ProxyFactory;
import javassist.util.proxy.ProxyObject;

public class JavassistProxyExample {
    public static void main(String[] args) throws Exception {
        // 创建代理工厂
        ProxyFactory factory = new ProxyFactory();
        factory.setSuperclass(UserService.class);

        // 设置方法拦截器
        MethodHandler handler = (self, thisMethod, proceed, args1) -> {
            System.out.println("Before method: " + thisMethod.getName());
            Object result = proceed.invoke(self, args1); // 调用原始方法
            System.out.println("After method: " + thisMethod.getName());
            return result;
        };

        // 生成代理对象
        Class<?> proxyClass = factory.createClass();
        UserService proxy = (UserService) proxyClass.getDeclaredConstructor().newInstance();
        ((ProxyObject) proxy).setHandler(handler);

        // 使用代理对象
        proxy.addUser("Tom");
    }
}

class UserService {
    public void addUser(String name) {
        System.out.println("Adding user: " + name);
    }
}

 

喜欢此文章就点个关注或收藏,常来看看就记住了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cra风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值