Java静态代理、动态代理

为什么要使用代理

设计模式中定义为:为其他对象提供一种代理以控制对这个对象的访问。
在某些情况下,一个客户不想或者不能直接引用另一个对象,此时代理对象可以在客户端和目标对象之间起到中介的作用。

代理分类

代理分为静态代理与动态代理
静态代理:由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
动态代理:在程序运行时,运用反射机制动态创建而成。
                    在Java中有两种实现方式,1、实现接口InvocationHandler;2、使用cglib。

代理示例

首先定义一个接口
package com.proxy;

public interface IPay {
void assemData(String msg);
void sendData(String data);
}

接口实现类
package com.proxy;


public class PayImpl implements IPay {


@Override
public void assemData(String msg) {
System.out.println("我是被代理的类,我被调用了。");
}


@Override
public void sendData(String data) {
System.out.println("我是被代理的类,我被调用了。");
}


}

静态代理
再定义一个接口的实现类,该类中会多出一个类型为IPay接口的实例变量
package com.proxy;


public class PayImpl1 implements IPay{
private IPay pay;


public PayImpl1(IPay pay) {
super();
this.pay = pay;
}


@Override
public void assemData(String msg) {
System.out.println("===before invoke===");
pay.assemData("发送银行的数据");
System.out.println("===after invoke===\r");
}


@Override
public void sendData(String data) {
System.out.println("===before invoke===");
pay.assemData("发送银行的数据");
System.out.println("===after invoke===\r");
}
}

测试代码
IPay pay = new PayImpl();
IPay payProxy = new PayImpl1(pay);
payProxy.assemData("发送到银行的数据");

运行效果
===before invoke===
我是被代理的类,我被调用了。
===after invoke===

动态代理
方式一
定义一个代理类,该代理类需要实现InvocationHandler接口,代码如下:
package com.proxy;


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
 * 动态代理类只能代理接口,代理类都需要实现接口InvocationHandler。
 * 被重写的invoke方法就是调用被代理接口的所有方法时需要调用的。
 * @author liuxd
 *
 */
public class DynamicProxy implements InvocationHandler {


private Object obj;


public DynamicProxy(Object obj) {
super();
this.obj = obj;
}


public static Object newInstance(Object obj) {
return java.lang.reflect.Proxy.newProxyInstance(obj.getClass()
.getClassLoader(), obj.getClass().getInterfaces(),
new DynamicProxy(obj));
}


@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result;
System.out.println("===before invoke===");
result = method.invoke(obj, args);
System.out.println("===after invoke===\r");
return result;
}


}

测试代码
IPay pay = new PayImpl();
IPay payProxy = (IPay) DynamicProxy.newInstance(pay);
payProxy.assemData("发送到银行的数据");

运行效果同上

方式二
package com.proxy;


import java.lang.reflect.Method;


import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;


/**
 * 使用cglib实现动态代理
 * 
 * @author liuxd
 * 
 */
public class CglibProxy implements MethodInterceptor {


private Object target = null;


public CglibProxy(Object target) {
super();
this.target = target;
}


/**
* 创建代理对象

* @param target
* @return
*/
public Object getProxy() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
// 回调方法
enhancer.setCallback(this);
// 创建代理对象
return enhancer.create();
}


@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
Object result = null;
System.out.println("===before invoke===");
result = proxy.invokeSuper(obj, args);
System.out.println("===after invoke===\r");
return result;
}


}

测试代码
PayImpl impl = new PayImpl();
CglibProxy cglib = new CglibProxy(impl);
PayImpl payProxy = (PayImpl) cglib.getProxy();
payProxy.assemData("发送到银行的数据");

运行效果同上

不知道大家注意到两种动态代理实现方式的区别没有,这里简单说下自己的研究结果:
实现InvocationHandler接口这种方式,其实在Proxy中它是使用$Proxy+顺序号 implements 你传入的接口这种方式动态的在jvm中生成了一个类实例,所以,你的业务类必须是接口、实现类的形式。
而使用cglib实现动态代理,它是动态生成了一个类,这个类继承了你传入的类,所以,你传入的类不用必须是接口、实现类这种形式,可以直接实现类。

各类代理特点

1、静态代理只能代理一个接口或实现类。

2、静态代理如果接口类发生了变化,那么,实现类、代理类都要进行调整。

3、动态代理可以代理多个接口类或实现类(cglib方式特有)。


你可能感兴趣的:(设计模式)