RPC的调用内部核心技术采用的就是动态代理。
示例代码:
package com.rpc.sample.proxy;
import sun.misc.ClassLoaderUtil;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JDKDynamicProxy {
/**
* 定义用户的接口
*/
public interface User {
String job();
}
/**
* 实际的调用对象
*/
public static class Teacher {
public String invoke(){
return "i'm a Teacher";
}
}
/**
* 创建JDK动态代理类
*/
public static class JDKProxy implements InvocationHandler {
private Object target;
JDKProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] paramValues) {
return ((Teacher)target).invoke();
}
}
public static void main(String[] args){
// 构建代理器
JDKProxy proxy = new JDKProxy(new Teacher());
ClassLoader classLoader = JDKDynamicProxy.class.getClassLoader();
// 生成代理类
User user = (User) Proxy.newProxyInstance(classLoader, new Class[]{User.class}, proxy);
// 接口调用
System.out.println(user.job());
}
}
代理类 $Proxy里面会定义相同签名的接口,然后内部会定义一个变量绑定JDKProxy代理对象,当调用 User.job接口方法,实质上调用的是JDKProxy.invoke()方法。
为什么要加入动态代理?
第一, 缺点: 不便于管理,不利于扩展维护。
第二, 优点: 可以做到拦截,添加其他额外功能。
1.Cglib 动态代理
Cglib是一个强大的、高性能的代码生成包。
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.21.0-GA</version>
</dependency>
示例代码:
public interface ProxyFactory {
<T> T getProxy(Object target, InvocationHandler handler) throws Throwable;
}
import com.bytebeats.codelab.javassist.proxy.ProxyFactory;
import java.lang.reflect.InvocationHandler;
public class JavassistProxyFactory implements ProxyFactory {
@Override
public <T> T getProxy(Object target, InvocationHandler handler) throws Throwable {
return (T) ProxyGenerator.newProxyInstance(Thread.currentThread().getContextClassLoader(),
target.getClass(), handler);
}
}
package com.bytebeats.codelab.javassist.proxy.javassist;
import com.bytebeats.codelab.javassist.util.ClassUtils;
import javassist.*;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
public class ProxyGenerator {
private static final AtomicInteger counter = new AtomicInteger(1);
private static ConcurrentHashMap<Class<?>, Object> proxyInstanceCache = new ConcurrentHashMap<>();
public static Object newProxyInstance(ClassLoader classLoader, Class<?> targetClass, InvocationHandler invocationHandler)
throws Exception {
if(proxyInstanceCache.containsKey(targetClass)){
return proxyInstanceCache.get(targetClass);
}
ClassPool pool = ClassPool.getDefault();
//生成代理类的全限定名
String qualifiedName = generateClassName(targetClass);
// 创建代理类
CtClass proxy = pool.makeClass(qualifiedName);
//接口方法列表
CtField mf = CtField.make("public static java.lang.reflect.Method[] methods;", proxy);
proxy.addField(mf);
CtField hf = CtField.make("private " + InvocationHandler.class.getName() + " handler;", proxy);
proxy.addField(hf);
CtConstructor constructor = new CtConstructor(new CtClass[]{pool.get(InvocationHandler.class.getName())}, proxy);
constructor.setBody("this.handler=$1;");
constructor.setModifiers(Modifier.PUBLIC);
proxy.addConstructor(constructor);
proxy.addConstructor(CtNewConstructor.defaultConstructor(proxy));
// 获取被代理类的所有接口
List<Class<?>> interfaces = ClassUtils.getAllInterfaces(targetClass);
List<Method> methods = new ArrayList<>();
for (Class cls : interfaces) {
CtClass ctClass = pool.get(cls.getName());
proxy.addInterface(ctClass);
Method[] arr = cls.getDeclaredMethods();
for (Method method : arr) {
int ix = methods.size();
Class<?> rt = method.getReturnType();
Class<?>[] pts = method.getParameterTypes();
StringBuilder code = new StringBuilder("Object[] args = new Object[").append(pts.length).append("];");
for(int j=0;j<pts.length;j++) {
code.append(" args[").append(j).append("] = ($w)$").append(j + 1).append(";");
}
code.append(" Object ret = handler.invoke(this, methods[" + ix + "], args);");
if(!Void.TYPE.equals(rt) )
code.append(" return ").append(asArgument(rt, "ret")).append(";");
StringBuilder sb = new StringBuilder(1024);
sb.append(modifier(method.getModifiers())).append(' ').append(getParameterType(rt)).append(' ').append(method.getName());
sb.append('(');
for(int i=0;i<pts.length;i++)
{
if( i > 0 )
sb.append(',');
sb.append(getParameterType(pts[i]));
sb.append(" arg").append(i);
}
sb.append(')');
Class<?>[] ets = method.getExceptionTypes(); //方法抛出异常
if( ets != null && ets.length > 0 )
{
sb.append(" throws ");
for(int i=0;i<ets.length;i++)
{
if( i > 0 )
sb.append(',');
sb.append(getParameterType(ets[i]));
}
}
sb.append('{').append(code.toString()).append('}');
CtMethod ctMethod = CtMethod.make(sb.toString(), proxy);
proxy.addMethod(ctMethod);
methods.add(method);
}
}
proxy.setModifiers(Modifier.PUBLIC);
Class<?> proxyClass = proxy.toClass(classLoader, null);
proxyClass.getField("methods").set(null, methods.toArray(new Method[0]));
Object instance = proxyClass.getConstructor(InvocationHandler.class).newInstance(invocationHandler);
Object old = proxyInstanceCache.putIfAbsent(targetClass, instance);
if(old!=null){
instance = old;
}
return instance;
}
private static String modifier(int mod) {
if( Modifier.isPublic(mod) ) return "public";
if( Modifier.isProtected(mod) ) return "protected";
if( Modifier.isPrivate(mod) ) return "private";
return "";
}
/**
* 数组类型返回 String[]
* @param c
* @return
*/
public static String getParameterType(Class<?> c) {
if(c.isArray()) { //数组类型
StringBuilder sb = new StringBuilder();
do {
sb.append("[]");
c = c.getComponentType();
} while( c.isArray() );
return c.getName() + sb.toString();
}
return c.getName();
}
private static String asArgument(Class<?> cl, String name) {
if( cl.isPrimitive() ) {
if( Boolean.TYPE == cl )
return name + "==null?false:((Boolean)" + name + ").booleanValue()";
if( Byte.TYPE == cl )
return name + "==null?(byte)0:((Byte)" + name + ").byteValue()";
if( Character.TYPE == cl )
return name + "==null?(char)0:((Character)" + name + ").charValue()";
if( Double.TYPE == cl )
return name + "==null?(double)0:((Double)" + name + ").doubleValue()";
if( Float.TYPE == cl )
return name + "==null?(float)0:((Float)" + name + ").floatValue()";
if( Integer.TYPE == cl )
return name + "==null?(int)0:((Integer)" + name + ").intValue()";
if( Long.TYPE == cl )
return name + "==null?(long)0:((Long)" + name + ").longValue()";
if( Short.TYPE == cl )
return name + "==null?(short)0:((Short)" + name + ").shortValue()";
throw new RuntimeException(name+" is unknown primitive type.");
}
return "(" + getParameterType(cl) + ")"+name;
}
private static String generateClassName(Class<?> type){
return String.format("%s$Proxy%d", type.getName(), counter.getAndIncrement());
}
}
几种动态代理性能比较:
Byte Buddy > Javassist > CGLIB > JDK
阅读量:2016
点赞量:0
收藏量:0