JAVA实现动态代理的两种方式

什么是动态代理?

动态代理(Dynamic Proxy)是一种在运行时动态生成代理对象的技术。它是一种设计模式,用于在不修改原始对象的情况下,通过代理对象来间接访问原始对象,并在访问前后执行额外的操作。也就是说,动态代理通过生成代理对象,可以扩展原对象的功能。
动态代理是实现面向切面的编程AOP(Aspect Oriented Programming)的基础。切面的例子有日志、性能监控、权限检查、数据库事务等,它们在程序的很多地方都会用到,代码都差不多,但与某个具体的业务逻辑关系也不太密切,如果在每个用到的地方都写,代码会很冗余,也难以维护,AOP将这些切面与主体逻辑相分离,代码简单优雅得多。

在Java中,实现动态代理有两种方式:
一种是通过JAVA SDK提供的,另一种是使用第三方库,如cdlib;

JDK实现动态代理

JDK动态代理主要通过两个核心类来实现:Proxy和InvocationHandler。Proxy类用于动态创建代理类,而InvocationHandler接口负责处理代理对象的方法调用。通过实现InvocationHandler接口,开发人员可以在代理对象的方法调用前后添加自定义的逻辑,实现对原始对象的控制和增强。
通过JDK实现动态代理要求被代理类,必须为接口;

  1. 创建接口和实现类
	interface IService{
        void sayHello();
    }
    static class RealService implements IService{

        @Override
        public void sayHello() {
            System.out.println("hello");
        }
    }

2.创建实现InvocationHandler的对象 ,在invoke方法调用代理对象的方法;

public simpleInvocationHandler(Object realObj) {
            this.realObj = realObj;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("entering "+method.getName());
            Object result = method.invoke(realObj, args);
            System.out.println("leaving "+method.getName());
            return result;
        }
    }
  1. 生成代理对象
    public static void main(String[] args) {
        RealService realService = new RealService();
        IService proxyInstance=(IService)Proxy.newProxyInstance(IService.class.getClassLoader(), new Class<?>[]{IService.class},new simpleInvocationHandler(realService));
        proxyInstance.sayHello();

    }

输出为

entering sayHello
hello
leaving sayHello
public static Object newProxyInstance(ClassLoader loader,
            Class<? >[] interfaces, InvocationHandler h)

它有三个参数,具体如下。
1)loader表示类加载器
2)interfaces表示代理类要实现的接口列表,是一个数组,元素的类型只能是接口,不能是普通的类,例子中只有一个IService。
3)h的类型为InvocationHandler,它是一个接口,也定义在java.lang.reflect包中,它只定义了一个方法invoke,对代理接口所有方法的调用都会转给该方法。
newProxyInstance的返回值类型为Object,可以强制转换为interfaces数组中的某个接口类型。这里我们强制转换为了IService类型,需要注意的是,它不能强制转换为某个类类型,比如RealService,即使它实际代理的对象类型为RealService。

cglib实现动态代理

Java SDK动态代理的局限在于,它只能为接口创建代理,返回的代理对象也只能转换到某个接口类型,如果一个类没有接口,或者希望代理非接口中定义的方法,那就没有办法了。有一个第三方的类库cglib(https://github.com/cglib/cglib),可以做到这一点,Spring、Hibernate等都使用该类库。
cglib实现动态代理,首先要导入cglib库
Maven项目导入依赖如下

		<dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.3.0</version>
        </dependency>

使用cglib生成代理对象如下


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

import java.lang.reflect.Method;

public class SimpleCGLibDemo {
    static class RealService{
        public void sayHello(){
            System.out.println("hello CGLib");
        }
    }
    static class SimpleInterceptor implements MethodInterceptor {

        @Override
        public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            System.out.println("entering "+method.getName());
            Object result = methodProxy.invokeSuper(o, args);
            System.out.println("leaving "+method.getName());
            return result;
        }
    }
    private static <T> T getProxy(Class<T> cls){
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(cls);
        enhancer.setCallback(new SimpleInterceptor());
        return (T)enhancer.create();
    }

    public static void main(String[] args) {
        RealService proxy = getProxy(RealService.class);
        proxy.sayHello();
    }
}

RealService表示被代理的类,它没有接口。getProxy()为一个类生成代理对象,这个代理对象可以安全地转换为被代理类的类型,它使用了cglib的Enhancer类。Enhancer类的setSuperclass设置被代理的类,setCallback设置被代理类的public非final方法被调用时的处理类。Enhancer支持多种类型,这里使用的类实现了MethodInterceptor接口,它与Java SDK中的InvocationHandler有点类似,方法名称变成了intercept,多了一个MethodProxy类型的参数。

与前面的InvocationHandler不同,SimpleInterceptor中没有被代理的对象,它通过MethodProxy的invokeSuper方法调用被代理类的方法:

    Object result = proxy.invokeSuper(object, args);

注意,它不能这样调用被代理类的方法:

    Object result = method.invoke(object, args);

object是代理对象,调用这个方法还会调用到SimpleInterceptor的intercept方法,造成死循环。
cglib的实现机制与Java SDK不同,它是通过继承实现的,它也是动态创建了一个类,但这个类的父类是被代理的类,代理类重写了父类的所有public非final方法,改为调用Callback中的相关方法,在上例中,调用SimpleInterceptor的intercept方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值