动态代理的使用

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();}@Overridepublic 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;}/*** 执行目标对象的方法*/@Overridepublic 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 {@Testpublic 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 permissionreturn 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;}}//创建subkeyObject 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> instanceV 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赋值为factorysupplier = factory;}// else retry with winning supplier} else {if (valuesMap.replace(subKey, supplier, factory)) {// successfully replaced// cleared CacheEntry / unsuccessful Factory// with our Factorysupplier = factory;} else {// retry with current suppliersupplier = valuesMap.get(subKey);}}}}

调用Factory对象的get方法

@Overridepublic synchronized V get() { // serialize access// re-checkSupplier<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 failurevaluesMap.remove(subKey, this);}}// the only path to reach here is with non-null valueassert 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 reverseMapreverseMap.put(cacheValue, Boolean.TRUE);} else {throw new AssertionError("Should not reach here");}// successfully replaced us with new CacheValue -> return the value// wrapped by itreturn 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 packageproxyPkg = 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 Proxyimplements 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

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

  1. aop实现原理 - JDK动态代理(实例+源码解析)

    动态代理: jdk代理-基于接口代理 通过 类:java.lang.reflect.Proxy 生成动态代理类 实现 接口:InvocationHandler 只能基于接口进行动态代理 代码实现: 1 ...

  2. JDK动态代理的实现原理

    学习JDK动态代理,从源码层次来理解其实现原理参考:http://blog.csdn.net/jiankunking/article/details/52143504 转载于:https://www. ...

  3. JDK 动态代理之源码解析

    过几天我会分享spring AOP 的相关的代理的源码,为了让大家学好springAOP ,今天先分析jdk 的动态代理 1.首先创建一个接口和一个被代理的对象: package com.nandao ...

  4. JDK动态代理用例及源码解析

    动态代理分为JDK 动态代理和CGLIB 动态代理 参考链接:https://www.jianshu.com/p/269afd0a52e6 一. JDK 动态代理 实现JDK动态代理必须实现接口. 实 ...

  5. JDK动态代理实现原理详解(源码分析)

    无论是静态代理,还是Cglib动态代理,都比较容易理解,本文就通过进入源码的方式来看看JDK动态代理的实现原理进行分析 要了解动态代理的可以参考另一篇文章,有详细介绍,这里仅仅对JDK动态代理做源码分 ...

  6. JDK动态代理底层源码剖析

    1. 动态代理相关概念 目标类:程序员自己写的.普通的业务类,是需要被代理的类: 目标方法:目标类中的实现业务的具体方法,为了精简,只写核心业务代码,因此需要代理类来增强功能: 增强器:是给目标方法增 ...

  7. jdk动态代理实例和cglib动态代理实例_CGLib 动态代理 原理解析

    JDK 动态代理实现与原理 首先来看一段CGLib代理的测试代码(MethodInterceptor的测试, 其他类型这里不做展开了). Util类的代码在后面给出的码云片段中 public 下面的输 ...

  8. 【动态代理】从源码实现角度剖析JDK动态代理

    相比于静态代理,动态代理避免了开发人员编写各个繁锁的静态代理类,只需简单地指定一组接口及目标类对象就能动态的获得代理对象.动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以不存在代 ...

  9. Jdk动态代理 底层源码分析

    前言 java动态代理主要有2种,Jdk动态代理.Cglib动态代理,本文主要讲解Jdk动态代理的使用.运行机制.以及源码分析.当spring没有手动开启Cglib动态代理,即:<aop:asp ...

最新文章

  1. 第一章:点云中的滤波问题---Filters
  2. SAP 序列号里主批次与库存批次不同,会有什么后果
  3. python怎么创建列表_用Python将一个列表分割成小列表的实例讲解 Python 如何创建一个带小数的列表...
  4. leetcode 整数反转
  5. kafka sink mysql,kafka之七 sinkTask详解
  6. Javaspring 1-6课 基本概念及第一个Javaspring程序
  7. 解决telnet: connect to address 127.0.0.1: Connection refused的错误信息问题
  8. [文摘20070816]家(周国平)
  9. 小米手环5表盘bin文件解包修改
  10. 通过 purge_relay_logs 自动清理relaylog
  11. 服务器晚上自动重启是什么原因,服务器经常自动重启是什么原因
  12. 无论用手工处理还是用计算机进行处理,会计电算化试卷
  13. [Python知识图谱] 一.哈工大pyltp安装及中文分句、中文分词、导入词典基本用法
  14. 区块链技术在创造共享经济方面胜过互联网
  15. 蓝桥杯 Python 练习题 Fibonacci数列
  16. ie input兼容 vue_IE浏览器兼容问题(基于vue)
  17. STM32开发基础知识——OLED开发基础
  18. Hexo站点SEO优化攻略
  19. 蹭个热度:我只希望孩子心中有爱,眼里有光……
  20. 3D检测论文阅读简记

热门文章

  1. 有礼 | 快来领取你的年终福利!
  2. 揭秘APP软件开发者——百万富翁之路(转)
  3. 为什么我(几乎)放弃了企业架构师。
  4. 经济学入门十人十书:大师级书单推荐
  5. NPU智能车基地招新
  6. 【MySQL】MySQL表之联合查询(多表查询)
  7. xbrl 数据比较分析_思考XML,使用XBRL分析财务报告
  8. mysql设置时间默认值
  9. 咱当爹的人, 有啥不一样
  10. ZooKeeper如何模拟会话失效(Session Expired)