JDK 1.3 版本后,Java提供了动态代理技术,允许应用在运行期创建接口的代理对象。
	
JDK 提供的代理只能针对接口做代理。也有更强大的代理库 cglib,可以实现对类的代理。
JDK 的 java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,Proxy类利用InvocationHandler动态创建一个符合某一接口的代理,生成(运行时)目标类的代理对象。
在普通编程过程中,无须使用动态代理,但在编写框架或底层基础代码时,动态代理的作用就非常大。
代理模式
**代理:**Proxy Pattern(即:代理模式),23种常用的面向对象软件的设计模式之一。
定义:**通过代理对象访问目标对象,这样做的目的可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能,代理对象可以在客户端和目标对象之间起到中介的作用。 
代理模式的关键有两个角色,代理对象 和 目标对象,代理对象是对目标对象的扩展,并调用目标对象。
理解举例:
代理对象可以形象的理解为经纪人角色,艺人则是目标对象,涉及市场的一些商演或活动的琐碎事项交给经纪人来处理,而主办方是通过经纪人找艺人演出(不能直接 new 艺人);经纪人可以负责多个艺人(动态)。
动态代理
Proxy
JDK 的 java.lang.reflect.Proxy类提供了static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)方法来获取代理对象。
- ClassLoader loader:指定代理对象的类加载器,加载代理类到 JVM 方法区。 
- Class<?>[] interfaces:指定代里类需要实现的接口,是个- Class数组,也就目标类可能实现多个接口。
 
- InvocationHandler:指调用具体的处理器实例,具体要处理的逻辑都在这个类实例里面。 - 执行目标对象方法时会触发该处理器的- invoke方法,会把当前执行目标对象的方法作为参数传入。
 
InvocationHandler
InvocationHandler的invoke(Object proxy, Method method, Object[] args)方法通过反射机制间接调用目标对象的方法,InvocationHandler可以更好的理解为编织器,这个特性是非常适用于AOP思想的实现的,可以将横切逻辑代码和目标业务类方法的业务逻辑编织在一起。
- Object proxy:最终生成的代理实例,一般用不到。
- Method method:被代理的目标对象的方法。
- Object[] args:方法需要的参数。
JDK动态代理使用步骤
- 一个接口和接口实现类。
- 一个实现了InvocationHandler接口的类,将目标对象做为该类的构造方法的参数传入。重写invoke方法,在该方法里添加目标类的扩展功能。
- 使用Proxy类调用newProxyInstance(),传入InvocationHandler对象来生成一个代理对象。
- 通过代理对象调用接口(目标对象实现的接口)里的方法,需要的话给接口里的方法传入参数。
实现示例一
接口
| 12
 3
 4
 5
 6
 7
 
 | 
 
 
 public interface HelloService {
 void sayHello(String name);
 }
 
 | 
实现类
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | 
 
 
 
 public class HelloServiceImpl implements HelloService{
 @Override
 public void sayHello(String name) {
 System.out.println("Hello, " + name);
 }
 }
 
 | 
代理类
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 
 | 
 
 
 
 
 
 public class HelloServiceProxy implements InvocationHandler {
 
 
 private Object target;
 
 
 
 
 
 
 public Object bind(Object target) {
 this.target = target;
 
 return Proxy.newProxyInstance(target.getClass().getClassLoader(),
 target.getClass().getInterfaces(), this);
 }
 
 
 
 
 
 
 
 
 @Override
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 System.out.println("..........这是JDK动态代理..........");
 
 System.out.println("代理前调用,我准备说Hello。");
 
 Object result = method.invoke(target, args);
 
 System.out.println("代理后调用,我已说过Hello了");
 return result;
 }
 }
 
 | 
测试
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | 
 
 
 public class HelloMain {
 
 public static void main(String[] args) {
 HelloServiceProxy helloServiceProxy = new HelloServiceProxy();
 HelloService proxy = (HelloService)helloServiceProxy.bind(new HelloServiceImpl());
 proxy.sayHello("Kitty");
 }
 }
 
 | 
实现示例二
一个接口
| 12
 3
 4
 5
 6
 
 | 
 
 public interface UserDao {
 void update(int id, String name);
 }
 
 | 
一个接口实现类
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | 
 
 public class UserDaoImpl implements UserDao {
 @Override
 public void update(int id, String name) {
 System.out.println("根据ID更新名称,id = " + id + "; name = " + name );
 }
 }
 
 | 
一个获取代理对象的类
Proxy.newProxyInstance()方法的InvocationHandler对象参数传入一个匿名的InvocationHandler对象。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 
 | public class UserDaoJdkProxy<T> {
 
 private T obj;
 
 
 public UserDaoJdkProxy(T obj) {
 this.obj = obj;
 }
 
 
 
 
 
 
 
 
 public Object getProxyInstance() {
 
 return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),
 new InvocationHandler() {
 
 @Override
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 
 System.out.println("开始事务。。。。。");
 
 Object methodValue = method.invoke(obj, args);
 System.out.println("结束事务。。。。。");
 return methodValue;
 }
 });
 }
 }
 
 | 
客户端调用代理对象执行目标方法
| 12
 3
 4
 5
 6
 7
 8
 
 | public class Client {
 public static void main(String[] args) {
 UserDao userDao = new UserDaoImpl();
 userDao = (UserDao) new UserDaoJdkProxy(userDao).getProxyInstance();
 userDao.update(100, "root");
 }
 }
 
 | 
实现示例三
自定义实现InvocationHandler接口的类
实现InvocationHandler接口,重写invoke方法,在该方法里做目标对象的功能扩展。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 
 | 
 
 public class CustomizeInvocationHandler implements InvocationHandler {
 
 
 private Object target;
 
 public CustomizeInvocationHandler(Object target) {
 this.target = target;
 }
 
 @Override
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 System.out.println("transaction begin....");
 Object object = method.invoke(target, args);
 System.out.println("transaction end....");
 return object;
 }
 }
 
 | 
或者
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 
 | 
 
 
 
 
 
 public class UserDaoJdkProxy<T> implements InvocationHandler {
 
 
 private T target;
 
 public UserDaoJdkProxy(T target) {
 this.target = target;
 }
 
 
 public Object getProxyObject() {
 
 return Proxy.newProxyInstance(target.getClass().getClassLoader(),
 target.getClass().getInterfaces(), this);
 }
 
 
 
 
 
 @Override
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 System.out.println("事务开启。。。。");
 Object result = method.invoke(target, args);
 System.out.println("事务结束。。。。");
 return result;
 }
 }
 
 | 
客户端调代理对象类创建代理对象,通过代理对象执行目标对象的方法
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | public class Client {
 public static void main(String[] args) {
 UserDao userDao = (UserDao) Proxy.newProxyInstance(UserDao.class.getClassLoader(),
 new Class[]{UserDao.class},
 new CustomizeInvocationHandler(new UserDaoImpl()));
 userDao.save(100L, "Kitty");
 
 UserDao userDao1 = new UserDaoImpl();
 UserDaoJdkProxy<UserDao> proxy = new UserDaoJdkProxy<>(userDao1);
 userDao1 = (UserDao) proxy.getProxyObject();
 userDao1.save(100L, "Kitty");
 }
 }
 
 | 
原理分析
JDK 的动态代理需要依赖接口,Proxy.newProxyInstance()需要传入目标对象实现的接口作为参数;也就是说如果目标对象没有实现接口,则无法使用JDK动态代理。查看该方法的原码,进行了验证、优化、缓存、同步、生成字节码,显示加载类等操作。
原码分析
Proxy.newProxyInstance():
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 
 | public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,
 InvocationHandler h)
 throws IllegalArgumentException
 {
 Objects.requireNonNull(h);
 
 final Class<?>[] intfs = interfaces.clone();
 final SecurityManager sm = System.getSecurityManager();
 if (sm != null) {
 checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
 }
 
 
 
 
 
 Class<?> cl = getProxyClass0(loader, intfs);
 
 
 
 
 try {
 if (sm != null) {
 checkNewProxyPermission(Reflection.getCallerClass(), cl);
 }
 
 final Constructor<?> cons = cl.getConstructor(constructorParams);
 final InvocationHandler ih = h;
 if (!Modifier.isPublic(cl.getModifiers())) {
 AccessController.doPrivileged(new PrivilegedAction<Void>() {
 public Void run() {
 cons.setAccessible(true);
 return null;
 }
 });
 }
 
 return cons.newInstance(new Object[]{h});
 } catch (IllegalAccessException|InstantiationException e) {
 throw new InternalError(e.toString(), e);
 } catch (InvocationTargetException e) {
 Throwable t = e.getCause();
 if (t instanceof RuntimeException) {
 throw (RuntimeException) t;
 } else {
 throw new InternalError(t.toString(), t);
 }
 } catch (NoSuchMethodException e) {
 throw new InternalError(e.toString(), e);
 }
 }
 
 | 
getProxyClass0()
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | private static Class<?> getProxyClass0(ClassLoader loader,
 Class<?>... interfaces) {
 
 if (interfaces.length > 65535) {
 throw new IllegalArgumentException("interface limit exceeded");
 }
 
 return proxyClassCache.get(loader, interfaces);
 }
 
 | 
相关参考
- 细说JDK动态代理的实现原理
- JDK动态代理实现原理
- 深入剖析JDK动态代理机制