java动态代理

写在前面

这边文章仅仅是使用动态代理的工具,主要使用jdk和cglib来生成代理对象;
关于java动态代理的介绍和原理就不在这边文章进行说明,在谷歌上一搜索就很多关于java动态代理的介绍,也可以自己研究代理的原理以及实现细节,该文章主要为后面的简单限流做代理支撑。

代理工具

  • jdk版本1.8
  • maven依赖如下
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.3.3.RELEASE</version>
</dependency>
代理回调接口定义

该接口主要用于代理触发的回调实现

package littlehow.proxy;

import java.lang.reflect.Method;

/**
 * 代理回调接口
 */
public interface ProxyCall {
    /**
     * 代理回调
     * @param method     -- 代理方法
     * @param arguments  -- 参数
     * @return   -- 方法返回值
     */
    Object invoke(Object instance, Method method, Object[] arguments) throws Throwable;
}

jdk代理
package littlehow.proxy;

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

public class InvocationProxy<T> implements InvocationHandler {
    private T instance;
    private ProxyCall call;
    /**
     * 生成代理对象
     * @param obj
     * @param <T> 接口类型
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> T newInstance(T obj, ProxyCall call) {
        InvocationProxy<T> invocationProxy = new InvocationProxy<>();
        Class<?> clazz = obj.getClass();
        invocationProxy.instance = obj;
        invocationProxy.call = call;
        return (T) Proxy.newProxyInstance(clazz.getClassLoader(),
                clazz.getInterfaces(), invocationProxy);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return call.invoke(instance, method, args);
    }
}

cglib代理(依赖spring)
package littlehow.proxy;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CglibProxy<T> implements MethodInterceptor {
    private T instance;
    private ProxyCall call;

    @SuppressWarnings("unchecked")
    public static <T> T newCglibInstance(T obj, ProxyCall call) {
        CglibProxy<T> cp = new CglibProxy<>();
        cp.instance = obj;
        cp.call = call;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(obj.getClass());
        enhancer.setCallback(cp);
        return (T)enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        return call.invoke(instance, method, objects);
    }
}

获取代理类工具
package littlehow.proxy;

public class ProxyUtils {

    /**
     * 获取代理对象
     * @param obj  -- 需要被代理的对象
     * @param proxyCall  -- 代理回调处理
     * @param <T>
     * @return
     */
    public static <T> T getProxyInstance(T obj, ProxyCall proxyCall) {
        if(obj == null) return null;
        //判断是否有接口,当前jdk版本返回的数组不可能为null,如果未实现接口,则数组长度为0
        Class<?>[] interfaces = obj.getClass().getInterfaces();
        if (interfaces == null || interfaces.length == 0) {//使用cglib代理
            return CglibProxy.newCglibInstance(obj, proxyCall);
        } else {//使用jdk代理
            return InvocationProxy.newInstance(obj, proxyCall);
        }
    }
}

简单测试

代理目标类
package littlehow.service;

import java.util.UUID;

public class UserService {
    public String add(String name, String sex) {
        System.out.println("新增用户 ---> 姓名:" + name + ", 性别:" + sex);
        return UUID.randomUUID().toString().replace("-", "");
    }
}

测试类(直接java主方法执行)
package littlehow.test.service;

import littlehow.proxy.ProxyUtils;
import littlehow.service.UserService;

import java.util.Arrays;

public class UserServiceTest {
    private static UserService service = ProxyUtils.getProxyInstance(new UserService(), (instance, method, arguments) -> {
        try {
            System.out.println("方法执行开始--->方法名:" + method.getName() + ",参数:" + Arrays.toString(arguments));
            return method.invoke(instance, arguments);
        } finally {
            System.out.println("方法执行结束");
        }
    });

    public static void main(String[] args) {
        String userId = service.add("littlehow", "male");
        System.out.println("用户编号:" + userId);
    }
}

执行结果为:

方法执行开始—>方法名:add,参数:[littlehow, male]

新增用户 —> 姓名:littlehow, 性别:male

方法执行结束

用户编号:6ad5b57b2dfa45eb943d283efb484448

结束语

该文章只讲解基本使用,进阶应用将在下一篇文章。


下篇文章将讲到简单限流的方式,以及自有代理和aspectJ在限流中如何选择以及原因,敬请期待.


littlehow 写于2019-04-26

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值