写在前面
这边文章仅仅是使用动态代理的工具,主要使用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