这两天在学反射机制与java动态代理.有点收获.在这里总结下
个人理解代理模式就是将本应该对一个类操作的事务由另一个类来代理完成.在代理类中可以进行一些前期准备工作于后期处理.
这样使得代理类可以在不同的地方有不同的表现.
代理模式经常被其他模式引用比如适配器.装饰.拦截器模式中都有代理模式的应用.
而java在代理模式的基础上为开发人员提供了一套机制.通过此套机制可以动态的生成代理类.与执行代理对象.而不用每个代理都写代理类.
当然java的这些是通过java的反射机制来实现的.
本人写了一个简单的java程序来实现java动态代理
package proxy;
import java.lang.reflect.*;
interface Talk{
void spoke(String str);
}
interface Sing{
void sing(String str);
}
class Mytalk implements Talk,Sing{
@Override
public void spoke(String str) {
System.out.println("说:"+str);
}
public void sing(String str) {
System.out.println("唱:"+str);
}
}
class Litalk implements Talk{
@Override
public void spoke(String str) {
System.out.println("说:"+str+",我是小李");
}
}
class client implements InvocationHandler{
private Object object;//代理的对象
client(Object object){
this.object=object;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
try{
// String stri1=object.getClass().getName();
// Class<?>[] tClass=object.getClass().getInterfaces();
// String string= tClass[0].getName();
System.out.println(object.getClass().getName()+"要说");//执行前预备工作
if(method.getName().equals("sing")){
System.out.print("大家注意.要唱歌了");
}
method.invoke(object, args);
System.out.println(object.getClass().getName()+"说完了");//执行后的工作
}
catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
return null;
}
public Object getObject() {
return object;
}
public void setObject(Object object) {
this.object = object;
}
}
public class TalkFactory{
//talk工厂获取talk的代理
@SuppressWarnings("unchecked")
public static<T> T getProxy(Class<T> intf, T obj) {
return (T) Proxy.newProxyInstance(obj.getClass().getClassLoader(),
new Class[] { intf },
new client(obj));
}
}
public class proxytest {
public static void main(String []str){
Litalk litalk =new Litalk();
Talk talk=TalkFactory.getProxy(Talk.class, litalk);
talk.spoke("asdf");
Mytalk mytalk =new Mytalk();
Talk talk1=TalkFactory.getProxy(Talk.class, mytalk);
talk1.spoke("asdf");
@SuppressWarnings("unused")
Mytalk mysing =new Mytalk();
Sing talk2=TalkFactory.getProxy(Sing.class, mytalk);
talk2.sing("asdf");
}
}
这是一个简单的例子,就是通过一个工厂来获取代理类,并在代理类做一些处理
输出结果
proxy.Litalk要说
说:asdf,我是小李
proxy.Litalk说完了
proxy.Mytalk要说
说:asdf
proxy.Mytalk说完了
proxy.Mytalk要说
大家注意.要唱歌了唱:asdf
proxy.Mytalk说完了
其中如果是唱歌的方法那么会多打印出一条语句.
在深入研究java的动态代理进入proxy的源码后
发现
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
if (h == null) {
throw new NullPointerException();
}
/*
* Look up or generate the designated proxy class.
*/
Class<?> cl = getProxyClass(loader, interfaces);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
Constructor cons = cl.getConstructor(constructorParams);
return cons.newInstance(new Object[] { h });
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString());
} catch (IllegalAccessException e) {
throw new InternalError(e.toString());
} catch (InstantiationException e) {
throw new InternalError(e.toString());
} catch (InvocationTargetException e) {
throw new InternalError(e.toString());
}
}
这是proxy中newProxyInstance的源码.
在Proxy中有一个变量
protected InvocationHandler h;
这是使代理类跳转到InvocationHandler 接口执行方法.
其中
Class<?> cl = getProxyClass(loader, interfaces);这句是最关键的他产生了一个类.这个类叫做$ProxyN
在深入看getProxyClass方法
开始是一些判断与异常处理
接着是处理接口
最后是这段
long num;
synchronized (nextUniqueNumberLock) {
num = nextUniqueNumber++;
}
String proxyName = proxyPkg + proxyClassNamePrefix + num;
/*
* Verify that the class loader hasn't already
* defined a class with the chosen name.
*/
/*
* Generate the specified proxy class.
*/
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());
}
}
// add to set of all generated proxy classes, for isProxyClass
proxyClasses.put(proxyClass, null);
proxy有一个hashtable将其中的代理类放入其中.在下次使用的时候如果有则直接取出不在重新生成.如果没有则生成新的代理类
在我上面的代码中
前两个都是talk接口所以他们两个使用一个代理类$Proxy0
最后一个代理Sing接口所以是$Proxy1
这段代码应该是核心代码其中proxyName 为申城代理类的名字 proxyClassFile 为生成的字节码文件proxyClass 就是生成的类.再进一步看ProxyGenerator类是发现此类是被保护的没有源码(java是全开源么..)defineClass0是一个native方法(果然还是c/c++效率高底层,还是用c/c++啊)..
在网上搜一些资料发现生成的Proxy类是通过调用super.h.invoke方法来实现方法执行的.
这些是我对java动态代理的一些理解和研究