首先我们需要了解一下什么是代理
代理:就是一个角色代表另一角色完成某些特定的功能。
例如:汽车制造商,4S店,客户
客户购买汽车并不直接与汽车制造商打交道,也不用知道汽车是如何制造的,客户只与4S店打交道,而4S店可以对汽车进行一些包装,提供一些保修、保险等相关售后的服务。
下面我们根据实际的Java例子来说明代理
代理模式有三个角色: 1. 抽象主题角色 2. 代理主题角色 3. 实际被代理角色
其它类通过访问代理主题角色来访问实际被代理角色。
1. 静态代理
抽象主题角色
package com.staticproxy;
/**
* 抽象主题角色
* @author ljf
*
*/
public interface StaticInterface {
public void dosomething();
}
代理主题角色
package com.staticproxy;
/**
* 代理主题角色
* @author ljf
*
*/
public class StaticProxy implements StaticInterface {
private StaticInterface staticInterface;
public StaticProxy(StaticInterface staticInterface){
this.staticInterface = staticInterface;
}
public void dosomething() {
System.out.println("我正在上班的路上....");
staticInterface.dosomething();
System.out.println("我正在下班的路上....");
}
}
实际被代理角色
package com.staticproxy;
/**
* 实际被代理角色
* @author ljf
*
*/
public class StaticTarget implements StaticInterface {
public void dosomething() {
System.out.println("我正在上班工作呢>>>>>");
}
}
静态代理测试
package com.staticproxy;
public class TestStaticProxy {
/**
* @param args
*/
public static void main(String[] args) {
StaticInterface staticTarget = new StaticTarget();
StaticProxy proxy = new StaticProxy(staticTarget);
proxy.dosomething();
}
}
测试结果
我正在上班的路上....
我正在上班工作呢>>>>>
我正在下班的路上....
从上例可以看到代理主题角色:StaticProxy实现了对StaticInterface的dosomething()方法,而StaticProxy,Statictarget都实现了StaticInterface接口,通过调用StaticProxy的dosomething()方法我们可以实现对Statictarget的dosomething()方法的调用,而不用在Statictarget的dosomething()方法中作任何实现,这就是代理的作用。代理实现StaticProxy时,Statictarget必需实现StaticInterface接口。因此如果我要在Statictarget的dosomething()方法前后加入更多的功能就需要写更多的主题代理角色,代码会显得很臃肿。因此可以可以动态的生成代理主题来代理所有被代理的对象。这就是动态代理。
2. 动态代理
(1)、简单实现动态代理
下面我们先自己实现一个简单的动态代理功能
类图如下:
首先编写一个抽象代理主题功能的类:Proxy
package com.dynamic.proxy;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import javax.tools.JavaCompiler.CompilationTask;
/**
* 实现抽象代理主题角色
* @author ljf
*
*/
public class Proxy {
public static Object newProxyIntenct(Class infac,MyInvocationHandler h) throws Exception{
String br ="\r\n";
String methString ="";
Method[] method = infac.getMethods();
for(Method m: method){
methString = " @Override"+ br +
" public void "+m.getName()+"() {"+ br +
" try {" + br +
" Method md ="+ infac.getName()+".class.getMethod(\""+m.getName()+"\");"+ br +
" h.myInvoke(this,md);" + br +
" }catch (Exception e){ "+ br+
" e.printStackTrace();" + br +
" }" + br +
" }";
}
String src =
"package com.dynamic.proxy;" + br +
"import java.lang.reflect.Method;" + br +
"public class $Proxy implements "+infac.getName()+"{" + br +
" private com.dynamic.proxy.MyInvocationHandler h;" + br +
" public $Proxy(MyInvocationHandler h) {" + br +
" super();" + br +
" this.h = h;" + br +
" }" + br + br +
methString +br +
"}";
//创建java目录
MakDirectUtil.createDirect("C:/ljf/workspace/demo/src/com/dynamic/proxy");
//生成java文件
String fileName ="C:\\ljf\\workspace\\demo\\src\\com\\dynamic\\proxy\\$Proxy.java";
System.out.println(fileName);
File file = new File(fileName);
FileWriter fWriter = new FileWriter(file);
fWriter.write(src);
fWriter.flush();
fWriter.close();
//生成class文件,jdk6提供的工具类
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
Iterable units = fileManager.getJavaFileObjects(fileName);
CompilationTask task = compiler.getTask(null, fileManager, null, null, null, units);
task.call();
fileManager.close();
//装载到内存,生成新对象
URL[] urls = new URL[]{new URL("file:/"+"C:\\ljf\\workspace\\demo\\src\\")};
URLClassLoader loader = new URLClassLoader(urls);
Class c = loader.loadClass("com.dynamic.proxy.$Proxy");
//通过有参的构造器反射生成代理类的实例
Constructor ctr = c.getConstructor(MyInvocationHandler.class);
Object obj = (Object) ctr.newInstance(h);
return obj;
}
}
代理对象接口:MyInvocationHandler
package com.dynamic.proxy;
import java.lang.reflect.Method;
/**
* 代理对象接口
* @author ljf
*
*/
public interface MyInvocationHandler {
void myInvoke(Object o,Method m);
}
代理对象:TimeInvocationHandler
package com.dynamic.proxy;
import java.lang.reflect.Method;
/**
* 代理对象
* @author ljf
*
*/
public class TimeInvocationHandler implements MyInvocationHandler {
//代理目标对象<Car>
private Object target;
public TimeInvocationHandler(Object target) {
super();
this.target = target;
}
public void myInvoke(Object o, Method m) {
long time1 = System.currentTimeMillis();
System.out.println("启动前时间="+time1);
try {
m.invoke(target);
} catch (Exception e) {
e.printStackTrace();
}
long time2 = System.currentTimeMillis();
System.out.println("启动后时间"+time2);
System.out.println("汽车的启动时间:"+(time2-time1));
}
}
被代理对象接口:Moveable
package com.dynamic.proxy;
/**
* 被代理对象接口
* @author ljf
*
*/
public interface Moveable {
public void move();
}
被代理对象:Car
package com.dynamic.proxy;
/**
* 被代理对象
* @author ljf
*
*/
public class Car implements Moveable {
public void move() {
int a = 5;
int b = 6;
int c = 0;
for (int i = 0; i < 1000000; i++) {
}
c = ((a+b)/2)*12;
System.out.println("Car moving..Car 的速度是"+c);
}
}
辅助创建目录功能类:MakDirectUtil
package com.dynamic.proxy;
import java.io.File;
import java.io.IOException;
import java.util.StringTokenizer;
/**
* 创建目录
* @author ljf
*
*/
public class MakDirectUtil {
public static void createDirect(String pathstr) throws IOException{
//创建多级目录
String path = pathstr;
//为指定字符串构造一个 string tokenizer。 "/"字符是分隔标记的分隔符。分隔符字符本身不作为标记。
StringTokenizer st = new StringTokenizer(path,"/");
String path1 = st.nextToken()+"/";
String path2 = path1;
while(st.hasMoreTokens())
{
path1 = st.nextToken()+"/";
path2 += path1;
File inbox = new File(path2);
if(!inbox.exists())
inbox.mkdir();
}
}
}
最后是测试类:
package com.dynamic.proxy;
/**
* 测试动态代理
* @author ljf
*
*/
public class TestCar {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Car car = new Car();
Moveable moveable = null;
try {
moveable = (Moveable) Proxy.newProxyIntenct(Moveable.class,new TimeInvocationHandler(car));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
moveable.move();
}
}
运行结果:
C:\ljf\workspace\demo\src\com\dynamic\proxy\$Proxy.java
启动前时间=1414722152895
Car moving..Car 的速度是60
启动后时间1414722152895
汽车的启动时间:0
(2)、jdk动态代理
接下来我们了解一下jdk的动态代理是如何实现的。
先看看jdk的动态代理是怎么使用的:
代理关联对象:MyInvocationHandler
package com.jdk.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 代理关联对象
* @author ljf
*
*/
public class MyInvocationHandler implements InvocationHandler {
//代理目标对象
private Object target;
public Object bindProxy(Object o) {
this.target = o;
Object proxy = Proxy.newProxyInstance(o.getClass().getClassLoader(), o.getClass().getInterfaces(), this);
return proxy;
}
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;
}
}
被代理对象接口:IFly
package com.jdk.proxy;
/**
* 被代理对象接口
* @author ljf
*
*/
public interface IFly {
public void fly();
}
被代理对象:Air
package com.jdk.proxy;
/**
* 被代理对象
* @author ljf
*
*/
public class Air implements IFly {
public void fly() {
System.out.println("飞机正在天空中平稳的飞翔....");
}
}
代理测试:TestjdkProxy
package com.jdk.proxy;
/**
* jdk动态代理测试类
* @author ljf
*
*/
public class TestjdkProxy {
/**
* @param args
*/
public static void main(String[] args) {
IFly air = new Air();
MyInvocationHandler handler = new MyInvocationHandler();
IFly proxy = (IFly) handler.bindProxy(air);
proxy.fly();
}
}
测试结果:
飞机正在跑道上准备起飞.....
飞机正在天空中平稳的飞翔....
飞机正在降落着陆的过程中....
用起来很方便吧,但是它究竟是怎么运作的呢,那我们接下来看看jdk源码是如何实现的。从上面看是使用的Proxy的静态方法newProxyInstance()。那我们就首先从它的源码来看:
/**
* loader:类加载器
* interfaces:目标对象实现的接口
* h:InvocationHandler的实现类
*/
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
//InvocationHandler不能为空,因为代理对象的所有方法调用实际都是通过委托InvocationHandler的invoke方法
if (h == null) {
throw new NullPointerException();
}
/*
* Look up or generate the designated proxy class.
*/
//这个是核心的地方,通过提供的ClassLoader和interface列表来产生代理类,具体的实现可以参考getProxyClass0这个方法的实现
Class<?> cl = getProxyClass0(loader, interfaces); // stack walk magic: do not refactor
/*
* Invoke its constructor with the designated invocation handler.
*/
//因为代理类继承了Proxy类.而Proxy中定义了构造函数protected Proxy(InvocationHandler h),所以可以反射得到Constructer实例
try { // 调用代理对象的构造方法(也就是$Proxy0(InvocationHandler h))
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
SecurityManager sm = System.getSecurityManager();
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(loader, interfaces)方法,我们接着进入该方法源码看看:
/**
* 使用特定的类加载器,加载某个类,从而得到此代理对象的Class
*/
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
final int CALLER_FRAME = 3; // 0: Reflection, 1: getProxyClass0 2: Proxy 3: caller
final Class<?> caller = Reflection.getCallerClass(CALLER_FRAME);
final ClassLoader ccl = caller.getClassLoader();
checkProxyLoader(ccl, loader);
ReflectUtil.checkProxyPackageAccess(ccl, interfaces);
}
if (interfaces.length > 65535) {//被代理对象实现的接口不可多于65535(好NB啊)
throw new IllegalArgumentException("interface limit exceeded");
}
Class proxyClass = null;//初始化代理对象
/* collect interface names to use as key for proxy class cache */
String[] interfaceNames = new String[interfaces.length];
Set interfaceSet = new HashSet(); // 避免接口重复
for (int i = 0; i < interfaces.length; i++) {
/*
* Verify that the class loader resolves the name of this
* interface to the same Class object.
*/
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");
}
/*
* Verify that the Class object actually represents an
* interface.
*/
if (!interfaceClass.isInterface()) {//不是接口抛出异常,jdk动态代理只能实现接口
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
/*
* Verify that this interface is not a duplicate.
*/
if (interfaceSet.contains(interfaceClass)) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
interfaceSet.add(interfaceClass);
interfaceNames[i] = interfaceName;
}
/*
* Using string representations of the proxy interfaces as
* keys in the proxy class cache (instead of their Class
* objects) is sufficient because we require the proxy
* interfaces to be resolvable by name through the supplied
* class loader, and it has the advantage that using a string
* representation of a class makes for an implicit weak
* reference to the class.
*/
Object key = Arrays.asList(interfaceNames);
/*
* Find or create the proxy class cache for the class loader.
*/
Map cache;
synchronized (loaderToCache) {
//同步类装载器的Cache
cache = (Map) loaderToCache.get(loader);
if (cache == null) {
cache = new HashMap();
//该Cache以类装载器为key,value也为一个Cache
loaderToCache.put(loader, cache);
}
/*
* This mapping will remain valid for the duration of this
* method, without further synchronization, because the mapping
* will only be removed if the class loader becomes unreachable.
*/
}
/*
* Look up the list of interfaces in the proxy class cache using
* the key. This lookup will result in one of three possible
* kinds of values:
* null, if there is currently no proxy class for the list of
* interfaces in the class loader,
* the pendingGenerationMarker object, if a proxy class for the
* list of interfaces is currently being generated,
* or a weak reference to a Class object, if a proxy class for
* the list of interfaces has already been generated.
*/
synchronized (cache) {
/*
* Note that we need not worry about reaping the cache for
* entries with cleared weak references because if a proxy class
* has been garbage collected, its class loader will have been
* garbage collected as well, so the entire cache will be reaped
* from the loaderToCache map.
*/
do {
//该Cache以Class数组为key以proxyClass为value
Object value = cache.get(key);
if (value instanceof Reference) {
//保存在Cache中的value为Reference
proxyClass = (Class) ((Reference) value).get();
}
if (proxyClass != null) {
// 代理对象已存在: 返回代理对象
return proxyClass;
} else if (value == pendingGenerationMarker) {
// 其他线程正在创建代理对象,本线程等待
try {
cache.wait();
} catch (InterruptedException e) {
/*
* The class generation that we are waiting for should
* take a small, bounded time, so we can safely ignore
* thread interrupts here.
*/
}
continue;
} else {
/*
* No proxy class for this list of interfaces has been
* generated or is being generated, so we will go and
* generate it now. Mark it as pending generation.
*/
cache.put(key, pendingGenerationMarker);
break;
}
} while (true);
}
try {
String proxyPkg = null; // 代理对象所在的包
/*
* Record the package of a non-public proxy interface so that the
* proxy class will be defined in the same package. Verify that
* all non-public proxy interfaces are in the same package.
*/
for (int i = 0; i < interfaces.length; i++) {//遍历Class数组
int flags = interfaces[i].getModifiers();//得到class的修饰符
if (!Modifier.isPublic(flags)) {//修饰符为public的类
String name = interfaces[i].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) {//非public代理类使用sun默认的包路径
// if no non-public proxy interfaces, use sun.proxy package
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
{
/*
* Choose a name for the proxy class to generate.
*/
long num;
synchronized (nextUniqueNumberLock) {
num = nextUniqueNumber++;
}
//代理对象名称:包名.$Proxy0,$Proxy1等等
String proxyName = proxyPkg + proxyClassNamePrefix + num;
/*
* Verify that the class loader hasn't already
* defined a class with the chosen name.
*/
/*
* 将指定名称代理类的.class文件转化为byte数组
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces);
try {
//根据代理类的字节码生成代理类的实例
proxyClass = defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
/*
* A ClassFormatError here means that (barring bugs in the
* proxy class generation code) there was some other
* invalid aspect of the arguments supplied to the proxy
* class creation (such as virtual machine limitations
* exceeded).
*/
throw new IllegalArgumentException(e.toString());
}
}
// 将新创建的ProxyClass放入Chche中
proxyClasses.put(proxyClass, null);
} finally {
/*
* We must clean up the "pending generation" state of the proxy
* class cache entry somehow. If a proxy class was successfully
* generated, store it in the cache (with a weak reference);
* otherwise, remove the reserved entry. In all cases, notify
* all waiters on reserved entries in this cache.
*/
synchronized (cache) {
if (proxyClass != null) {
cache.put(key, new WeakReference(proxyClass));
} else {
cache.remove(key);
}
cache.notifyAll();
}
}
return proxyClass;
}
接着我们再看看newInstance()方法:
private static Object newInstance(Constructor<?> cons, InvocationHandler h) {
try {
// 生成代理类的实例并把MyInvocationHandler的实例传给它的构造方法
return cons.newInstance(new Object[] {h} );
} catch (IllegalAccessException e) {
throw new InternalError(e.toString());
} catch (InstantiationException e) {
throw new InternalError(e.toString());
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString());
}
}
}
最后我们再看一下Proxy里面的一些变量
/** 代理对象名称前缀 */
private final static String proxyClassNamePrefix = "$Proxy";
/** 代理对象实例化时需要的的构造参数 */
private final static Class[] constructorParams =
{ InvocationHandler.class };
/** 类转载器的cache */
private static Map loaderToCache = new WeakHashMap();
/** 表示某个代理对象正在被创建 */
private static Object pendingGenerationMarker = new Object();
/** 代理对象被创建的个数,初始化时为0 */
private static long nextUniqueNumber = 0;
/** 此同步过程使代理被创建的数目唯一 */
private static Object nextUniqueNumberLock = new Object();
/** set of all generated proxy classes, for isProxyClass implementation */
private static Map proxyClasses =
Collections.synchronizedMap(new WeakHashMap());
/**
* the invocation handler for this proxy instance.
* @serial
*/
protected InvocationHandler h;
现在,JDK是怎样动态生成代理类的字节的原理我们已经基本了解了。有那么几个关键点1.目标对象必须实现接口;2.目标对象实现的接口数目不得超过65535;3.生成的代理对象都是以$Proxy+数字来命名。所以跟我平时老说的jdk动态代理必须要实现接口的说法一致了吧。
import com.jdk.proxy.IFly;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0 extends Proxy
implements IFly
{
private static Method m1;
private static Method m3;
private static Method m0;
private static Method m2;
//构造方法,参数就是刚才传过来的MyInvocationHandler类的实例
public $Proxy0(InvocationHandler paramInvocationHandler)
{
super(paramInvocationHandler);
}
public final boolean equals(Object paramObject)
{
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 void fly()
{
try
{
/*
* 实际上就是调用MyInvocationHandler的
* public Object invoke(Object proxy, Method method, Object[] args)方法
* 第二个问题就解决了
*/
this.h.invoke(this, m3, null);
return;
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final int hashCode()
{
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()
{
try
{
return (String)this.h.invoke(this, m2, null);
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
/*
* 在静态代码块中获取了4个方法:Object中的equals方法
* IFly中的fly方法、Object中的hashCode方法、Object中toString方法
*/
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m3 = Class.forName("com.jdk.proxy.IFly").getMethod("fly", new Class[0]);
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());
}
}
}
到此,jdk的动态代理分析就完成了,下一编文章我们再看看CGLIB动态代理。