动态代理类的源码是程序在运行期间由JVM根据反射等机制动态生成的,所以不存在代理类的字节码文件。代理角色和真实角色的联系在程序运行时确定!
Java中有两种动态代理,一种是JDK自带的,另一种的CGLIB动态代理。
jdk方式,委托类必须实现接口,代理类只能对接口进行代理。使用java的反射机制,以及Proxy和InvocationHandler来实现,代理类与委托类实现了相同的接口。
CGLIB(code generate library),代理类可对类进行代理,使用第三方cglib库来实现,其内部使用asm框架生成代理类的字节码,其字节码文件更加复杂,不能代理final方法,因为代理类是委托类的子类。
下面介绍的是JDK自带的动态代理:
代码结构:
/** * 抽象角色,真实对象和代理对象共同的接口 * @author Administrator * */ public interface IUserInfo { public void queryUser(); }
/** * 真实角色 * @author Administrator * */ public class JdkDynamicProxy implements IUserInfo{ @Override public void queryUser() { System.out.println("真实角色查询方法"); } }
/** * 代理角色处理器 * * @author Administrator * */ public class UserHandler 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("真实方法前做一些事情"); Object object = method.invoke(target, args);// 这里调用的就是真实方法,target对象是通过反射调用 System.out.println("真实方法后做一些事情"); return object; } }
/** * 调用 * @author Administrator * */ public class Test { public static void main(String[] args) { IUserInfo userImpl = new JdkDynamicProxy();//创建真实对象 UserHandler handler = new UserHandler();//绑定,生成代理对象 IUserInfo userInfo = (IUserInfo) handler.bind(userImpl); userInfo.queryUser(); } }