JDK动态代理实现原理
JDK的动态代理是怎样创建的,InvocationHandler的invoke方法是由谁来调用的,代理对象是怎么生成的。这些问题是JDK动态代理学习中碰到的一些问题。
首先,我们来看怎样生成Class的实例。
在这里,我将使用反射来创建JDK实例,并支持传入Class名称,构造方法参数列表,字段的Map来创建实例
1 package com.proxy; 2 3 import java.lang.reflect.Constructor; 4 import java.lang.reflect.InvocationTargetException; 5 import java.lang.reflect.Method; 6 import java.util.Map; 7 8 /** 9 * 实例创建器 10 */ 11 public class InstanceBuilder { 12 13 /** 14 * 根据类名创建对象 15 * @param className 类名 16 * @return 17 * @throws ClassNotFoundException 18 * @throws IllegalAccessException 19 * @throws InstantiationException 20 */ 21 public static Object builderInstance(String className) throws ClassNotFoundException, IllegalAccessException, InstantiationException { 22 if (null == className || className.length() == 0) { 23 throw new ClassNotFoundException("The Class name is blank, please check your spelling."); 24 } 25 Class clazz = Class.forName(className); 26 Object obj = clazz.newInstance(); 27 return obj; 28 } 29 30 /** 31 * 根据类名、构造方法参数创建实例对象 32 * @param className 类名 33 * @param constructorParams 构造方法参数 34 * @return 35 * @throws ClassNotFoundException 36 * @throws IllegalAccessException 37 * @throws InvocationTargetException 38 * @throws InstantiationException 39 */ 40 public static Object builderInstance(String className, Object[] constructorParams) throws ClassNotFoundException, IllegalAccessException, InvocationTargetException, InstantiationException { 41 if (null == constructorParams || constructorParams.length == 0) { 42 return builderInstance(className); 43 } 44 Class clazz = Class.forName(className); 45 Constructor[] constructors = clazz.getConstructors(); 46 Object result = null; 47 for (Constructor constructor: constructors) { 48 Integer paramCount = constructor.getParameterTypes().length; 49 if (checkParamsType(constructor.getParameterTypes(), constructorParams)) { 50 result = constructor.newInstance(constructorParams); 51 break; 52 } 53 } 54 if (null != result) { 55 return result; 56 } else { 57 throw new InstantiationException("The Class instantiation failure."); 58 } 59 } 60 61 /** 62 * 根据类名、构造方法参数创建对象,并设置字段值 63 * @param className 类名 64 * @param constructorParams 构造方法参数 65 * @param attributeParams 字段值 66 * @return 67 * @throws ClassNotFoundException 68 * @throws InvocationTargetException 69 * @throws InstantiationException 70 * @throws IllegalAccessException 71 */ 72 public static Object builderInstance(String className, Object[] constructorParams, Map attributeParams) throws ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException { 73 Object obj = builderInstance(className, constructorParams); 74 // 字段参数为空,不处理 75 if (null == attributeParams || attributeParams.isEmpty()) { 76 return obj; 77 } 78 /** 79 * TODO 暂时只处理set方法注入 80 */ 81 Method[] methods = obj.getClass().getDeclaredMethods(); 82 for (Method method: methods) { 83 String methodName = method.getName(); 84 String fieldName = resolveMethodName(methodName); 85 if (null != fieldName && attributeParams.containsKey(fieldName)) { 86 method.invoke(obj, attributeParams.get(fieldName)); 87 } 88 } 89 return obj; 90 } 91 92 /** 93 * 检查构造方法参数是否匹配 94 * @param parameterTypes 构造方法类型 95 * @param params 构造方法参数 96 * @return 97 */ 98 private static boolean checkParamsType(Class[] parameterTypes, Object[] params) { 99 Integer paramCount = parameterTypes.length; 100 if (paramCount != params.length) { 101 return false; 102 } 103 for (int i = 0; i < paramCount; i++) { 104 Class parameterType = parameterTypes[i]; 105 // 判断方法参数类型与传入的参数类型是否相同 106 if (! parameterType.isInstance(params[i])) { 107 System.out.println("The Parameter is not match the ParameterType."); 108 return false; 109 } 110 } 111 return true; 112 } 113 114 /** 115 * 根据方法名解析字段 116 * @param methodName 方法名 117 * @return 解析后的字段 118 */ 119 private static String resolveMethodName(String methodName) { 120 if (! methodName.startsWith("set") && methodName.startsWith("is")) { 121 return null; 122 } 123 // 方法名长度 124 int nameLength = methodName.length(); 125 // 处理方法前面的set,并将首字母转成大写形式 126 if (methodName.startsWith("set") && nameLength >= 4) { 127 int pos = 3; 128 String fieldName = methodName.substring(pos, nameLength); 129 char beginChar = methodName.charAt(pos); 130 fieldName = fieldName.replace(beginChar, Character.toLowerCase(beginChar)); 131 return fieldName; 132 } 133 return null; 134 } 135 136 }
上面的代码已经能够用来创建Class的实例了,接下来,我们来看怎样实现动态代理。
首先我们定义以下接口与实现类
接口: UserService
package com.proxy; public interface UserService { boolean sayHello(); boolean sayHello(String name); }
实现类: UserServiceImpl
1 package com.proxy; 3 public class UserServiceImpl implements UserService { 4 5 private String name; 7 private Integer age; 8 9 public UserServiceImpl() { 11 } 12 13 public UserServiceImpl(String name) { 14 this.name = name; 15 } 16 17 public UserServiceImpl(String name, Integer age) { 18 this.name = name; 19 this.age = age; 20 } 21 22 @Override 23 public boolean sayHello() { 24 sayHello(this.name); 25 return true; 26 } 27 28 @Override 29 public boolean sayHello(String name) { 30 System.out.println("hello, " + name + "!"); 31 System.out.println("age: " + this.age + "!"); 32 return true; 33 } 34 35 public String getName() { 36 return name; 37 } 39 public void setName(String name) { 40 this.name = name; 41 } 43 public Integer getAge() { 44 return age; 45 } 47 public void setAge(Integer age) { 48 this.age = age; 49 } 51 }
我们使用JDK动态代理来创建代理对象,这里我定义一个Handler
1 package com.proxy; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.InvocationTargetException; 5 import java.lang.reflect.Method; 6 import java.lang.reflect.Proxy; 7 import java.util.Map; 8 9 /** 10 * 动态代理处理方法 11 */ 12 public class DefaultInvocationHandler implements InvocationHandler { 17 private Class clazz; // 目标Class 18 private String className; // 类名 19 private Object[] params; // 构造方法参数数组 20 private Map attributes; // 字段属性 21 22 private Object instance; // 创建的实例对象 23 24 public DefaultInvocationHandler(Class clazz) { 25 super(); 26 this.clazz = clazz; 27 } 28 29 public DefaultInvocationHandler(Class clazz, Object[] params) { 30 super(); 31 this.clazz = clazz; 32 this.params = params; 33 } 34 35 public DefaultInvocationHandler(Class clazz, Object[] params, Map attributes) { 36 super(); 37 this.clazz = clazz; 38 this.params = params; 39 this.attributes = attributes; 40 } 41 42 /** 43 * 实例化对象 44 * @return 45 */ 46 private void instantObject() { 47 if (null != instance) { 48 return; 49 } 50 this.className = this.clazz.getName(); 51 Object obj = null; 52 try { 53 obj = InstanceBuilder.builderInstance(className, params, attributes); 54 } catch (ClassNotFoundException e) { 55 e.printStackTrace(); 56 } catch (InvocationTargetException e) { 57 e.printStackTrace(); 58 } catch (InstantiationException e) { 59 e.printStackTrace(); 60 } catch (IllegalAccessException e) { 61 e.printStackTrace(); 62 } 63 this.instance = obj; 64 } 65 66 /** 67 * 执行目标对象方法 68 * @param proxy 代理对象 69 * @param method 方法 70 * @param args 参数 71 * @return 72 * @throws Throwable 73 */ 74 @Override 75 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 77 // 实例化对象 78 instantObject(); 80 // 方法调用之前执行的操作 81 System.out.println("-------- before --------"); 82 // 调用方法 83 Object result = method.invoke(instance, args); 84 // 方法调用之后执行的操作 85 System.out.println("--------- end ----------"); 87 return result; 88 } 89 90 /** 91 * 获取目标类的代理对象 92 * @return 93 */ 94 public Object getProxy() { 95 return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), this.clazz.getInterfaces(), this); 96 } 97 }
测试代码如下:
1 package com.proxy; 2 3 import java.util.HashMap; 4 import java.util.Map; 5 6 public class MainTest { 7 8 public static void main(String[] args) { 9 10 //无构造方法、无参数 11 //fun1(); 12 13 // 有构造方法、无参数 14 //fun2(); 15 16 // 无构造方法、有参数 17 //fun3(); 18 19 // 有构造方法、有参数 20 fun4(); 21 22 } 23 24 /** 25 * 无构造方法、无参数 26 */ 27 private static void fun1() { 28 // 实例化InvocationHandler 29 DefaultInvocationHandler invocationHandler = new DefaultInvocationHandler(UserServiceImpl.class); 30 31 // 根据目标生成代理对象 32 UserService userService = (UserService) invocationHandler.getProxy(); 33 34 System.out.println(userService.sayHello("张飞")); 35 } 36 37 /** 38 * 有构造方法、无参数 39 */ 40 private static void fun2() { 41 Object[] params = new Object[] {"李四", 23}; 42 // 实例化InvocationHandler 43 DefaultInvocationHandler invocationHandler = new DefaultInvocationHandler(UserServiceImpl.class, params); 44 45 // 根据目标生成代理对象 46 UserService userService = (UserService) invocationHandler.getProxy(); 47 48 System.out.println(userService.sayHello()); 49 } 50 51 /** 52 * 无构造方法、有参数 53 */ 54 private static void fun3() { 55 Map<String, Object> attributes = new HashMap<String, Object>(); 56 attributes.put("name", "王五"); 57 attributes.put("age", 25); 58 // 实例化InvocationHandler 59 DefaultInvocationHandler invocationHandler = new DefaultInvocationHandler(UserServiceImpl.class, null, attributes); 60 61 // 根据目标生成代理对象 62 UserService userService = (UserService) invocationHandler.getProxy(); 63 64 System.out.println(userService.sayHello()); 65 } 66 67 /** 68 * 有构造方法、有参数 69 */ 70 private static void fun4() { 71 Object[] params = new Object[] {"赵六", 23}; 72 Map<String, Object> attributes = new HashMap<String, Object>(); 73 attributes.put("age", 25); 74 75 // 实例化InvocationHandler 76 DefaultInvocationHandler invocationHandler = new DefaultInvocationHandler(UserServiceImpl.class, params, attributes); 77 78 // 根据目标生成代理对象 79 UserService userService = (UserService) invocationHandler.getProxy(); 80 81 System.out.println(userService.sayHello()); 82 } 83 }
经过以上步骤,已经能够根据实现类的Class来创建动态代理对象,并能够执行动态代理对象的代理方法。
后面将考虑使用动态代理来干预程序的执行。