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来创建动态代理对象,并能够执行动态代理对象的代理方法。

后面将考虑使用动态代理来干预程序的执行。

 

posted @ 2018-04-25 20:08  雪域熊猫  阅读(168)  评论(0编辑  收藏  举报