java动态代理
两种:
1.JDK Proxy
2.cglib
JDK动态代理与CGLib动态代理均是实现Spring AOP的基础。
一、JDK Proxy
1.示例:
/**
* 具体实现类的接口
*/
public interface Subject {
public void rent();
}
/**
* 具体实现类
*/
public class RealSubject implements Subject {
public void rent() {
System.out.println("具体实现类的方法");
}
}
/**
* 创建动态代理类
*/
public class DynamicProxy implements InvocationHandler {
//这个就是我们要代理的真实对象
private Object subject;
//构造方法,给我们要代理的真实对象赋初值
public DynamicProxy(Object subject){
this.subject = subject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//在代理真实对象前我们可以添加一些自己的操作
System.out.println("之前");
//当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
method.invoke(subject, args);
// 在代理真实对象后我们也可以添加一些自己的操作
System.out.println("之后");
return null;
}
}
/**
* test
*/
public class Client {
public static void main(String[] args){
//我们要代理的真实对象
Subject realSubject = new RealSubject();
//我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的
InvocationHandler handler = new DynamicProxy(realSubject);
/*
* 通过Proxy的newProxyInstance方法来创建我们的代理对象,我们来看看其三个参数
* 第一个参数 handler.getClass().getClassLoader() ,我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象
* 第二个参数realSubject.getClass().getInterfaces(),我们这里为代理对象提供的接口是真实对象所实行的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了
* 第三个参数handler, 我们这里将这个代理对象关联到了上方的 InvocationHandler 这个对象上
*/
Subject subject = (Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject
.getClass().getInterfaces(), handler);
subject.rent();
}
}
2.源码分析
TODO
一个典型的动态代理创建对象过程可分为以下四个步骤:
1、通过实现InvocationHandler接口创建自己的调用处理器 IvocationHandler handler = new InvocationHandlerImpl(...);
2、通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类
Class clazz = Proxy.getProxyClass(classLoader,new Class[]{...});
3、通过反射机制获取动态代理类的构造函数,其参数类型是调用处理器接口类型
Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});
4、通过构造函数创建代理类实例,此时需将调用处理器对象作为参数被传入
Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));
生成的代理对象ProxySubject继承Proxy类实现Subject接口,
实现的Subject的方法实际调用处理器的invoke方法,
而invoke方法利用反射调用的是被代理对象的的方法(Object result = method.invoke(proxied,args))
4.生成的代理类源码
原文:http://blog.csdn.net/scplove/article/details/52451899
原文:http://rejoy.iteye.com/blog/1627405
import java.lang.reflect.*;
public final class $Proxy11 extends Proxy
implements UserService
{
// 构造方法,参数就是刚才传过来的MyInvocationHandler类的实例
public $Proxy11(InvocationHandler invocationhandler)
{
super(invocationhandler);
}
public final boolean equals(Object obj)
{
try
{
return ((Boolean)super.h.invoke(this, m1, new Object[] {
obj
})).booleanValue();
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
/**
* 这个方法是关键部分
*/
public final void add()
{
try
{
// 实际上就是调用MyInvocationHandler的public Object invoke(Object proxy, Method method, Object[] args)方法,第二个问题就解决了
super.h.invoke(this, m3, null);
return;
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final int hashCode()
{
try
{
return ((Integer)super.h.invoke(this, m0, null)).intValue();
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final String toString()
{
try
{
return (String)super.h.invoke(this, m2, null);
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
private static Method m1;
private static Method m3;
private static Method m0;
private static Method m2;
// 在静态代码块中获取了4个方法:Object中的equals方法、UserService中的add方法、Object中的hashCode方法、Object中toString方法
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {
Class.forName("java.lang.Object")
});
m3 = Class.forName("dynamic.proxy.UserService").getMethod("add", 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]);
}
catch(NoSuchMethodException nosuchmethodexception)
{
throw new NoSuchMethodError(nosuchmethodexception.getMessage());
}
catch(ClassNotFoundException classnotfoundexception)
{
throw new NoClassDefFoundError(classnotfoundexception.getMessage());
}
}
}
二、cglib Proxy
http://blog.csdn.net/yakoo5/article/details/9099133/
JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类,如何实现动态代理呢,这就需要CGLib了。
CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,
并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。
1.示例
import java.lang.reflect.*;
public final class $Proxy11 extends Proxy
implements UserService
{
// 构造方法,参数就是刚才传过来的MyInvocationHandler类的实例
public $Proxy11(InvocationHandler invocationhandler)
{
super(invocationhandler);
}
public final boolean equals(Object obj)
{
try
{
return ((Boolean)super.h.invoke(this, m1, new Object[] {
obj
})).booleanValue();
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
/**
* 这个方法是关键部分
*/
public final void add()
{
try
{
// 实际上就是调用MyInvocationHandler的public Object invoke(Object proxy, Method method, Object[] args)方法,第二个问题就解决了
super.h.invoke(this, m3, null);
return;
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final int hashCode()
{
try
{
return ((Integer)super.h.invoke(this, m0, null)).intValue();
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final String toString()
{
try
{
return (String)super.h.invoke(this, m2, null);
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
private static Method m1;
private static Method m3;
private static Method m0;
private static Method m2;
// 在静态代码块中获取了4个方法:Object中的equals方法、UserService中的add方法、Object中的hashCode方法、Object中toString方法
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {
Class.forName("java.lang.Object")
});
m3 = Class.forName("dynamic.proxy.UserService").getMethod("add", 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]);
}
catch(NoSuchMethodException nosuchmethodexception)
{
throw new NoSuchMethodError(nosuchmethodexception.getMessage());
}
catch(ClassNotFoundException classnotfoundexception)
{
throw new NoClassDefFoundError(classnotfoundexception.getMessage());
}
}
}
2.反编译生成的代理对象源码
http://www.cnblogs.com/ctgulong/p/5011614.html
三、JDK/CGLIB两种动态代理--比较
JDK创建动态代理,基于接口,需要具体实现类实现接口,
CGLIB创建动态代理,基于子类。final方法,无法进行代理。
CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,
但是CGLib在创建代理对象时所花费的时间却比JDK多得多,
所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。
四、Spring AOP分析
http://blog.csdn.net/jzq114/article/details/51346083
TODO