JDK动态代理的使用和源码解析(jdk1.7)

动态代理的使用

JDK动态代理只能给实现接口的类生成代理对象,主要用来通过JDK动态代理能够在不修改对象方法的前提下,修改方法内容.

1. 接口 UserService.java 

package cn.bing.jdkproxy;

public interface UserService {
	public void sayHello();
}

2. 实现类,需要生成代理对象的类 UserServiceImpl.java

package cn.bing.jdkproxy;

public class UserServiceImpl implements UserService {
	public UserServiceImpl(){super();}
	@Override
	public void sayHello() {
		System.out.println("hello world!");
	}

}

3. 生成代理类,改变对象行为

   需求:

   在调用sayHello前,输出 --- before ----

    调用sayHello后------after ------

   核心是调用方法 java.lang.reflect.Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 

生成代理对象。 

参数说明: 

loader  类加载器 ,使用当前类的类加载器就行

interfaces: 需要生成代理对象的类的接口的类对象,可以通过Class.getInterfaces获取

h: InvocationHandler接口的实现类对象,实现这个类,重写invoke方法,增加一些方法,在调用原方法前后

package cn.bing.jdkproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class MyInvocationHandler implements InvocationHandler{

	private Object object;
	public MyInvocationHandler(){}
	public MyInvocationHandler(Object obj){
		this.object = obj;
	}
	/**
	 * 执行目标对象的方法
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		System.out.println("-------before--------");
		Object invoke = method.invoke(this.object, args);
		System.out.println("-------after----------");
		return invoke;
	}
	/**
	 * 生成目标对象的代理对象
	 * @return
	 */
	public Object getProxy(){
		return Proxy.newProxyInstance(this.getClass().getClassLoader(), this.object.getClass().getInterfaces(), this);
	}
}

4. 执行,生成代理对象

package cn.bing.jdkproxy.junit;

import org.junit.Test;

import cn.bing.jdkproxy.MyInvocationHandler;
import cn.bing.jdkproxy.UserService;
import cn.bing.jdkproxy.UserServiceImpl;

public class ProxyJunit {
	@Test
	public void test(){
		UserService userService = new UserServiceImpl();
		MyInvocationHandler handler = new MyInvocationHandler(userService);
		UserService proxy = (UserService)handler.getProxy();
		proxy.sayHello();
	}
}

输出:

-------before--------
hello world!
-------after----------
hello world!

   JDK动态代理源码解析

首先看下核心方法:Proxy.newProxyInstance

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        if (h == null) {
            throw new NullPointerException();
        }
	
        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        //获取生成的代理的Class对象
        Class<?> cl = getProxyClass0(loader, intfs);
      
        try {
		    //利用反射生成构造器
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) {
                // create proxy instance with doPrivilege as the proxy class may
                // implement non-public interfaces that requires a special permission
                return AccessController.doPrivileged(new PrivilegedAction<Object>() {
                    public Object run() {
					    //构造器对象生成代理对象
                        return newInstance(cons, ih);
                    }
                });
            } else {
			    //构造器对象生成代理对象
                return newInstance(cons, ih);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString());
        }
    }

调用getProxyClass0方法生成代理对象的类对象

 private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
 private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }

        //WeakCache的get方法获取
        return proxyClassCache.get(loader, interfaces);
    }

//WeakCache类的构造方法
 public WeakCache(BiFunction<K, P, ?> subKeyFactory,
                     BiFunction<K, P, V> valueFactory) {
        this.subKeyFactory = Objects.requireNonNull(subKeyFactory);
        this.valueFactory = Objects.requireNonNull(valueFactory);
    }

调用WeakCache的get方法

public V get(K key, P parameter) {
        Objects.requireNonNull(parameter);

        expungeStaleEntries();

        Object cacheKey = CacheKey.valueOf(key, refQueue);

        
        ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
        if (valuesMap == null) {
            ConcurrentMap<Object, Supplier<V>> oldValuesMap
                = map.putIfAbsent(cacheKey,
                                  valuesMap = new ConcurrentHashMap<>());
            if (oldValuesMap != null) {
                valuesMap = oldValuesMap;
            }
        }
		//创建subkey
        Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
       //第一次,valuesMap是新创建的,这里获取supplier是空的
        Supplier<V> supplier = valuesMap.get(subKey);
        Factory factory = null;
		//从这里开始看
        while (true) {
		    第三步: 最终调用factory的get方法获取代理对象
            if (supplier != null) {
                // supplier might be a Factory or a CacheValue<V> instance
                V value = supplier.get();
                if (value != null) {
                    return value;
                }
            }
			//第一步:supperlier为空,首先创建factory对象
            if (factory == null) {
                factory = new Factory(key, parameter, subKey, valuesMap);
            }
            if (supplier == null) {
                supplier = valuesMap.putIfAbsent(subKey, factory);
                if (supplier == null) {
                    // 第二步:这里将supplier赋值为factory
                    supplier = factory;
                }
                // else retry with winning supplier
            } else {
                if (valuesMap.replace(subKey, supplier, factory)) {
                    // successfully replaced
                    // cleared CacheEntry / unsuccessful Factory
                    // with our Factory
                    supplier = factory;
                } else {
                    // retry with current supplier
                    supplier = valuesMap.get(subKey);
                }
            }
        }
    }

 调用Factory对象的get方法

@Override
        public synchronized V get() { // serialize access
            // re-check
            Supplier<V> supplier = valuesMap.get(subKey);
            //检查supplier的值是否和当前的值一致,可能因为多线程环境下,发生改变
            //再次检查
            if (supplier != this) {
               return null;
            }
            V value = null;
            try {
                //这是核心方法,获取代理对象
                value = Objects.requireNonNull(valueFactory.apply(key, parameter));
            } finally {
                if (value == null) { // remove us on failure
                    valuesMap.remove(subKey, this);
                }
            }
            // the only path to reach here is with non-null value
            assert value != null;

            // wrap value with CacheValue (WeakReference)
            CacheValue<V> cacheValue = new CacheValue<>(value);

            // try replacing us with CacheValue (this should always succeed)
            if (valuesMap.replace(subKey, this, cacheValue)) {
                // put also in reverseMap
                reverseMap.put(cacheValue, Boolean.TRUE);
            } else {
                throw new AssertionError("Should not reach here");
            }

            // successfully replaced us with new CacheValue -> return the value
            // wrapped by it
            return value;
        }
    }

最终是调用ProxyClassFactory的apply方法获取代理对象:

 public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {

            Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
            for (Class<?> intf : interfaces) {
               //创建Class对象放到一个interfaceSet 里面
               ...........
            }
            //代理类的全类型名
            String proxyPkg = null;     

            /*
             * 如果接口不是public接口,定义的代理类将存放在同一个包里面
             */
            for (Class<?> intf : interfaces) {
                int flags = intf.getModifiers();
                if (!Modifier.isPublic(flags)) {
                    String name = intf.getName();
                    int n = name.lastIndexOf('.');
                    String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
                    if (proxyPkg == null) {
                        proxyPkg = pkg;
                    } else if (!pkg.equals(proxyPkg)) {
                        throw new IllegalArgumentException(
                            "non-public interfaces from different packages");
                    }
                }
            }

            if (proxyPkg == null) {
                // 如果是公共的接口,代理类的包名称为 com.sun.proxy package
                proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
            }

            /*
             * 生成代理类的名称
             */
            long num = nextUniqueNumber.getAndIncrement();
            String proxyName = proxyPkg + proxyClassNamePrefix + num;

            /*
             * 生成代理类的二进制数组
             */
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces);
            try {//根据代理类的字节码,生成代理类对象
                return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
            } catch (ClassFormatError e) {
                throw new IllegalArgumentException(e.toString());
            }
        }
    }

进去ProxyGenerator.generateProxyClass方法看下,生成二进制数组的过程

public static byte[] generateProxyClass(String paramString, Class[] paramArrayOfClass)
{
  ProxyGenerator localProxyGenerator = new ProxyGenerator(paramString, paramArrayOfClass);
  //生成文件的二进制码
  final byte[] arrayOfByte = localProxyGenerator.generateClassFile();
  //如果是true,将文件写到硬盘上   
  if (saveGeneratedFiles) {
    AccessController.doPrivileged(new PrivilegedAction()
    {
      public Void run() {
        try {
          FileOutputStream localFileOutputStream = new FileOutputStream(ProxyGenerator.dotToSlash(this.val$name) + ".class");
          
          localFileOutputStream.write(arrayOfByte);
          localFileOutputStream.close();
          return null;
        } catch (IOException localIOException) {
          throw new InternalError("I/O exception saving generated file: " + localIOException);
        }
      }
    });
  }
  

  return arrayOfByte;
}

最后,测试下,将代理文件写到本地磁盘

@Test
public void writeToHard(){
		 byte[] bt = ProxyGenerator.generateProxyClass("$Proxy1", UserServiceImpl.class.getInterfaces());
		 try{
			 FileOutputStream out = new FileOutputStream(new File("c:/$Proxy1.class"));
			 out.write(bt);
			 out.flush();
			 out.close();
		 }catch(Exception e){
			 e.printStackTrace();
		 }
}

看下,反编译后的代理类的代码
 

import cn.bing.jdkproxy.UserService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy1 extends Proxy
  implements UserService
{
  private static Method m3;
  private static Method m1;
  private static Method m0;
  private static Method m2;

  public $Proxy1(InvocationHandler paramInvocationHandler)
    throws 
  {
    super(paramInvocationHandler);
  }

  public final void sayHello()
    throws 
  {
    try
    {
      this.h.invoke(this, m3, null);
      return;
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    }
    throw new UndeclaredThrowableException(localThrowable);
  }

  public final boolean equals(Object paramObject)
    throws 
  {
    try
    {
      return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    }
    throw new UndeclaredThrowableException(localThrowable);
  }

  public final int hashCode()
    throws 
  {
    try
    {
      return ((Integer)this.h.invoke(this, m0, null)).intValue();
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    }
    throw new UndeclaredThrowableException(localThrowable);
  }

  public final String toString()
    throws 
  {
    try
    {
      return (String)this.h.invoke(this, m2, null);
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    }
    throw new UndeclaredThrowableException(localThrowable);
  }

  static
  {
    try
    {
      m3 = Class.forName("cn.bing.jdkproxy.UserService").getMethod("sayHello", new Class[0]);
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      return;
    }
    catch (NoSuchMethodException localNoSuchMethodException)
    {
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }
    catch (ClassNotFoundException localClassNotFoundException)
    {
    }
    throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
  }
}

关注点:

1. 创建的代理对象是继承了Proxy,java里面只能是单继承,也就意味着如果一个类只是extends其他类(没有实现接口),就不能生成代理对象。

2. 从sayHello方法里面,我们看到实际上的调用invocationhandler的invoke方法,这里才回去调用invoke方法。

参考文章:http://rejoy.iteye.com/blog/1627405

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本项目是一个基于SpringBoot开发的华府便利店信息管理系统,使用了Vue和MySQL作为前端框架和数据库。该系统主要针对计算机相关专业的正在做毕设的学生和需要项目实战练习的Java学习者,包含项目源码、数据库脚本、项目说明等,有论文参考,可以直接作为毕设使用。 后台框架采用SpringBoot,数据库使用MySQL,开发环境为JDK、IDEA、Tomcat。项目经过严格调试,确保可以运行。如果基础还行,可以在代码基础之上进行改动以实现更多功能。 该系统的功能主要包括商品管理、订单管理、用户管理等模块。在商品管理模块中,可以添加、修改、删除商品信息;在订单管理模块中,可以查看订单详情、处理订单状态;在用户管理模块中,可以注册、登录、修改个人信息等。此外,系统还提供了数据统计功能,可以对销售数据进行统计和分析。 技术实现方面,前端采用Vue框架进行开发,后端使用SpringBoot框架搭建服务端应用。数据库采用MySQL进行数据存储和管理。整个系统通过前后端分离的方式实现,提高了系统的可维护性和可扩展性。同时,系统还采用了一些流行的技术和工具,如MyBatis、JPA等进行数据访问和操作,以及Maven进行项目管理和构建。 总之,本系统是一个基于SpringBoot开发的华府便利店信息管理系统,使用了Vue和MySQL作为前端框架和数据库。系统经过严格调试,确保可以运行。如果基础还行,可以在代码基础之上进行改动以实现更多功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值