您的位置:首页 > 编程语言 > Java开发

【深入JAVA】JDK静动态代理

2015-06-10 18:16 429 查看
静态代理:是由程序员创建或特定工具自动生成源代码,再对其进行编译,在程序运行前,代理类的.class文件就已经存在

动态代理:在程序运行时,代理类的.class文件是运用反射机制动态创建而成

一、静态代理

1> 定义一个接口Count

/**
* 自定义接口
* @author xwu
*
*/
public interface Count {
//查看账户
public void queryCount();
//更新账户
public void updateCount();
}
2>编写实现类

package com.wuxiao.proxy.staticProxy;

/**
* 接口实现类
*
* @author xwu
*
*/
public class CountImpl implements Count {

public void queryCount() {
// TODO Auto-generated method stub
System.out.println("调用查看账户方法...");
}

public void updateCount() {
// TODO Auto-generated method stub
System.out.println("调用更新账户方法...");
}

}
3>编写Count的代理类

package com.wuxiao.proxy.staticProxy;

/**
* Count的代理类CountProxy
*
* @author xwu
*
*/
public class CountProxy implements Count {

private CountImpl countImpl;

public CountProxy(CountImpl countImpl) {
this.countImpl = countImpl;
}

public void queryCount() {
System.out.println("方法调用之前...");
countImpl.queryCount();// 调用委托方法
System.out.println("方法调用之后...");
}

public void updateCount() {
System.out.println("方法调用之前...");
countImpl.updateCount();// 调用委托方法
System.out.println("方法调用之后...");
}

}
4>编写测试类

package com.wuxiao.proxy.staticProxy;

/**
* 静态代理测试类
*
* @author xwu
*
*/
public class StaticProxyTest {

public static void main(String[] args) {
CountImpl countImpl = new CountImpl();
CountProxy proxy = new CountProxy(countImpl);
proxy.queryCount();
proxy.updateCount();
}

}
5>看一下运行效果

方法调用之前...
调用查看账户方法...
方法调用之后...
方法调用之前...
调用更新账户方法...
方法调用之后...

总结:一个代理类只能为一个接口服务,如果需要代理的接口很多,那么开发过程中将编写大量的代理类,而且所有的代理操作除了调用的方法不一样,其他的操作都一样,这样就造成了大量的重复工作,不会偷懒的程序猿不是好的攻城狮,因此我们可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理了。

二、JDK动态代理

1>自定义一个接口(同上)

2>编写实现类(同上)

3>编写JDK核心代理类

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
* 切面
*
* @author xwu
*
*/
public class JDKProxyFactory implements InvocationHandler {

private Object proxyObject; // 目标对象

public Object createProxyInstance(Object proxyObject) {
this.proxyObject = proxyObject;

// 生成代理类的字节码加载器
ClassLoader classLoader = proxyObject.getClass().getClassLoader();
// 需要代理的接口,被代理实现的多个接口都必须定义在这里(这是一个缺陷,cglib弥补了这一缺陷)
Class<?>[] proxyInterface = proxyObject.getClass().getInterfaces();
// 织入器,织入代码并生成代理类
return Proxy.newProxyInstance(classLoader, proxyInterface, this);
}

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
PersonServiceBean bean = (PersonServiceBean) this.proxyObject;
Object result = null;
// 控制哪些用户切入逻辑,这里是做了用户名过滤,当然你也可以做其他事情
if (bean.getUser() != null) {
// 执行原有逻辑
result = method.invoke(this.proxyObject, args);
}
return result;
}

}
4>编写测试类

package com.wuxiao.proxy;

/**
* 通过main方法,并设置sun.misc.ProxyGenerator.saveGeneratedFiles参数可以查看生成的proxy文件
*
* @author xwu
*
*/
public class JDKProxyTest {

public static void main(String[] args) {
// 设置此系统属性,以查看代理类文件
System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

JDKProxyFactory factory = new JDKProxyFactory();
PersonService bean = (PersonService) factory.createProxyInstance(new PersonServiceBean("lucy"));
bean.save("abc");// 用户lucy有权限

PersonService bean2 = (PersonService) factory.createProxyInstance(new PersonServiceBean());
bean2.save("abc");// 用户为null没有权限
}

}
5>看看运行效果

这是save方法


总结:JDK动态代理依靠接口实现,没有实现接口的类则不能使用JDK动态代理,这也是JDK动态代理的一个缺陷吧,不过在cglib中得到了弥补.

这个时候我们可以看看程序运行过程中生成的代理类,run上面的main方法之后可以在当前工程根目录中发现一个$Proxy0.class文件,使用反编译工具打开后可以看到具体内容,下面是我测试代码生成的的.class

import com.wuxiao.proxy.PersonService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
//代理继承了Proxy类,并实现了Proxy.newProxyInstance中传入的接口
public final class $Proxy0 extends Proxy
implements PersonService
{
//这些方法在下面的static体中进行了初始化
private static Method m5;
private static Method m3;
private static Method m1;
private static Method m0;
private static Method m4;
private static Method m2;
//构造函数,接收一个InvocationHandler作为参数,这就是为什么Proxy.newProxyInstance方法里
//可以通过InvocationHandler实例作为参数来反射获取Constructer实例
public $Proxy0(InvocationHandler paramInvocationHandler)
throws
{
super(paramInvocationHandler);
}
//同下面的save方法
public final void update(Integer paramInteger, String paramString)
throws
{
try
{
this.h.invoke(this, m5, new Object[] { paramInteger, paramString });
return;
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
//下面通过这个save方法来看看代理对象中的方法是如何调用的
public final void save(String paramString)
throws
{
try
{
//全部是通过调用InvocationHandler的invoke方法,传入对应的方法和参数
this.h.invoke(this, m3, new Object[] { paramString });
return;
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
public final boolean equals(Object paramObject)
throws
{
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 int hashCode()
throws
{
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 getPersonName(Integer paramInteger)
throws
{
try
{
return (String)this.h.invoke(this, m4, new Object[] { paramInteger });
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
public final String toString()
throws
{
try
{
return (String)this.h.invoke(this, m2, null);
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
static
{
try
{
m5 = Class.forName("com.wuxiao.proxy.PersonService").getMethod("update", new Class[] { Class.forName("java.lang.Integer"), Class.forName("java.lang.String") });
m3 = Class.forName("com.wuxiao.proxy.PersonService").getMethod("save", new Class[] { Class.forName("java.lang.String") });
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m4 = Class.forName("com.wuxiao.proxy.PersonService").getMethod("getPersonName", new Class[] { Class.forName("java.lang.Integer") });
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());
}
}


需要解释的地方已经注释在代码中,应该还算清晰明了,后续会贴上cglib的代理还有Spring AOP动态代理的应用

------------------------------

end   by   wuxiao
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java proxy 动态代理