首先写一个解答的JDK代理例子
目标对象及接口
代理工厂实现
测试类(注意只能用接口接收)
这是为什么要用接口接收呢?下面我们取进入代理工厂的Proxy.newProxyInstance(?,?,?)方法
可以通过下面的源码清楚的看到
- public static Class<?> getProxyClass(ClassLoader loader,
- Class<?>... interfaces)
- throws IllegalArgumentException
- {
- // 如果目标类实现的接口数大于65535个则抛出异常(我XX,谁会写这么NB的代码啊?)
- if (interfaces.length > 65535) {
- throw new IllegalArgumentException("interface limit exceeded");
- }
- // 声明代理对象所代表的Class对象(有点拗口)
- Class proxyClass = null;
- String[] interfaceNames = new String[interfaces.length];
- Set interfaceSet = new HashSet(); // for detecting duplicates
- // 遍历目标类所实现的接口
- for (int i = 0; i < interfaces.length; i++) {
- // 拿到目标类实现的接口的名称
- String interfaceName = interfaces[i].getName();
- Class interfaceClass = null;
- try {
- // 加载目标类实现的接口到内存中
- interfaceClass = Class.forName(interfaceName, false, loader);
- } catch (ClassNotFoundException e) {
- }
- if (interfaceClass != interfaces[i]) {
- throw new IllegalArgumentException(
- interfaces[i] + " is not visible from class loader");
- }
- // 中间省略了一些无关紧要的代码 .......
- // 把目标类实现的接口代表的Class对象放到Set中
- interfaceSet.add(interfaceClass);
- interfaceNames[i] = interfaceName;
- }
- // 把目标类实现的接口名称作为缓存(Map)中的key
- Object key = Arrays.asList(interfaceNames);
- Map cache;
- synchronized (loaderToCache) {
- // 从缓存中获取cache
- cache = (Map) loaderToCache.get(loader);
- if (cache == null) {
- // 如果获取不到,则新建地个HashMap实例
- cache = new HashMap();
- // 把HashMap实例和当前加载器放到缓存中
- loaderToCache.put(loader, cache);
- }
- }
- synchronized (cache) {
- do {
- // 根据接口的名称从缓存中获取对象
- Object value = cache.get(key);
- if (value instanceof Reference) {
- proxyClass = (Class) ((Reference) value).get();
- }
- if (proxyClass != null) {
- // 如果代理对象的Class实例已经存在,则直接返回
- return proxyClass;
- } else if (value == pendingGenerationMarker) {
- try {
- cache.wait();
- } catch (InterruptedException e) {
- }
- continue;
- } else {
- cache.put(key, pendingGenerationMarker);
- break;
- }
- } while (true);
- }
- try {
- // 中间省略了一些代码 .......
- // 这里就是动态生成代理对象的最关键的地方
- byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
- proxyName, interfaces);
- try {
- // 根据代理类的字节码生成代理类的实例
- proxyClass = defineClass0(loader, proxyName,
- proxyClassFile, 0, proxyClassFile.length);
- } catch (ClassFormatError e) {
- throw new IllegalArgumentException(e.toString());
- }
- }
- // add to set of all generated proxy classes, for isProxyClass
- proxyClasses.put(proxyClass, null);
- }
- // 中间省略了一些代码 .......
- return proxyClass;
- }
核心:代码的目的就是将目标对象的接口实现的字节码并存放再内存中,再根据字节码生成代理类的实现(实现了接口)
- 下面看看生成字节码的地方
-
创建对象的时候调用InvocationHandler的invoke方法生成实现接口的代理类即可,注意实现类是继$Proxy implemnts 所有接口,所以只能用接口去接收,而不能实现类(这才是真正的原因)