利用JDK动态代理给接口创建动态实现

本文介绍了如何使用JDK动态代理技术为一个接口创建动态实现。通过示例展示了在没有手动编写实现类的情况下,接口方法依然能够正常调用的过程。文章包含SaleService接口、SaleInvocation(实现InvocationHandler接口)和ProxyTest测试类的源码解析。

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

我们大家都知道,一般情况下,如果一个接口没有实现类的话,我们直接调用该接口的方法会报错。但我们用过的Mybatis中Dao接口,或者Spring Data JPA接口,其实我们没有手动为他们编写实现类,那为什么仍然能正常调用呢?这里就涉及到了动态代理。下面我演示一下,如何利用JDK为一个接口创建动态实现。

代码目录大致如下,在com.company.proxy包下有三个类文件

一、SaleService 这个是一个接口声明,后面我们将为该接口创建一个动态实现。其源码如下:

package com.company.proxy;

/**
 *
 * @author LICHUANG
 */
public interface SaleService {

    /**
     * 出售
     * @param goodsName 商品名称
     * @param price 价格
     * @return
     */
    String sale(String goodsName,Integer price);
}

二、SaleInvocation 该类实现了InvocationHandler接口,并重写其invoke方法。其源码如下:

package com.company.proxy;

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

/**
 *
 * @author LICHUANG
 */
public class SaleInvocation implements InvocationHandler {

    private Class<?> clazz;

    public SaleInvocation(Class<?> o) {
        this.clazz = o;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //一般DEBUG时,我们查看变量时,会调用其toString()方法,由于该方法也会被代理,所以出现递归调用,
        //这里为了避免DEBUG时,重复调用方法,所以作特殊处理
        if (Object.class.equals(method.getDeclaringClass())) {
            return method.invoke(this,args);
        }
        System.out.println("调用前");
        //这里是为接口的方法构造实现逻辑,
        // 由于我们已经获取到了方法名称和参数值,所以可以根据实际需要去创建实现逻辑。
        Object result = "方法名称:" + method.getName() + ",参数值:" + Arrays.toString(args) + ",clazz:" + clazz;
        System.out.println("调用后result:" + result);
        return result;
    }
}

三、ProxyTest 这个类主要是包含main方法,用来测试的。其源码如下:

package com.company.proxy;

import java.lang.reflect.Proxy;

/**
 * 
 *
 * @author LICHUANG
 */
public class ProxyTest {

    public static void main(String[] args) {
        Class<?> clazz = SaleService.class;
        SaleInvocation invocation = new SaleInvocation(clazz);
        SaleService proxyObject = (SaleService) Proxy.newProxyInstance(clazz.getClassLoader(),new Class[] {clazz},invocation);
        String result = proxyObject.sale("商品名称",5);
        System.out.println("得到返回结果:" + result);
    }
}

可以注意到,以上SaleService接口,我并没有手动编写任何实现类,但我仍然能正常调用其String sale(String goodsName,Integer price)方法。

最后main方法运行结果如下:

调用前
调用后result:方法名称:sale,参数值:[商品名称, 5],clazz:interface com.company.proxy.SaleService
得到返回结果:方法名称:sale,参数值:[商品名称, 5],clazz:interface com.company.proxy.SaleService

Process finished with exit code 0

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值