代理模式是常用的Java设计模式,它的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。
代理类可以分为静态代理和动态代理。
1.静态代理
由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
程序示例:
step1:定义委托类
public interface Email {
public void send();
public void receive();
}
public class FlashEmail implements Email {
@Override
public void send() {
// TODO Auto-generated method stub
System.out.println("邮件发送中。。。。。");
}
@Override
public void receive() {
// TODO Auto-generated method stub
System.out.println("邮件接受中..........");
}
}
step2:定义代理类,与委托类有同样的接口
不改变原接口实现类的情况下,就可以对接口的功能进行需求变更
public class EmailProxy implements Email {
Email email;
//传入委托类初始化代理类
public EmailProxy(Email email)
{
this.email=email;
}
@Override
public void send() {
System.out.println("发送邮件前准备。。。");
email.send();
System.out.println("发送后。。。。。。");
}
@Override
public void revieve() {
System.out.println("接受邮件前准备。。。");
email.receive();
System.out.println("接受邮件成功....");
}
}
step3:测试代码:
public class Main {
public static void main(String[] args) {
//原始对象
Email email=new FlashEmail();
//接口的代理类
EmailProxy ep=new EmailProxy(email);
ep.send();
System.out.println("-----------------------------------------");
ep.receive();
}
}
测试结果:
发送邮件前准备。。。
邮件发送中。。。。。
发送后。。。。。。
-----------------------------------------
接受邮件前准备。。。
邮件接受中..........
接受邮件成功....
2 动态代理
动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。
java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。这一个类和接口是实现我们动态代理所必须用到的。
(1)Proxy类
Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下的操作方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
throws IllegalArgumentException
参数说明
- ClassLoader loader:一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
- Class<?>[] interfaces:一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给 它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
- InvocationHandler h: 一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个 InvocationHandler对象上
(2)InvocationHandler 接口
I
InvocationHandler是由代理实例的调用处理程序实现的接口 。每个代理实例都有一个关联的调用处理程序。 当在代理实例上调用方法时,方法调用将被编码并分派到其调用处理程序的invoke
方法。
如果想要完成动态代理,首先需定义一个InvocationHandler接口的子类,以完成代理要完成的具体操作。下面介绍InvocationHandler 接口的 invoke 方法,我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用!
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
- proxy: 指代我们所代理的那个真实对象
- method: 指代的是我们所要调用真实对象的某个方法的Method对象
- args: 指代的是调用真实对象某个方法时接受的参数
程序示例:
step1:定义委托类
public interface Email {
public void send();
public void revieve();
}
public class FlashEmail implements Email {
@Override
public void send() {
// TODO Auto-generated method stub
System.out.println("邮件发送中。。。。。");
}
@Override
public void revieve() {
// TODO Auto-generated method stub
System.out.println("邮件接受中..........");
}
}
step2:在使用动态代理时,我们需要定义一个位于代理类与委托类之间的中介类,也叫动态代理类,以完成代理要完成的具体操作,这个类被要求实现InvocationHandler接口:
public class MyInvocationHandler implements InvocationHandler {
Object obj;//委托对象
public MyInvocationHandler(Object obj) {
super();
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if("send".equals(method.getName())) {
System.out.println("发送邮件前准备。。。");
method.invoke(obj);//从委托对象中,调用该对象的指定方法,这里相当于send方法
System.out.println("发送后。。。。。。");
}
if("receive".equals(method.getName())) {
System.out.println("接受邮件前准备。。。");
method.invoke(obj);
System.out.println("接受邮件成功....");
}
return null;
}
}
step3:定义代理类工厂,用于动态生成代理类
public class ProxyFactory {
Object obj;
public ProxyFactory(Object obj) {
super();
this.obj = obj;
}
public static Object createProxy(Object obj)
{
MyInvocationHandler mch=new MyInvocationHandler(obj);
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), mch);
}
}
step4:测试
public class Main {
public static void main(String[] args) {
Email email=new FlashEmail();
Email emailProxy=(Email) ProxyFactory.createProxy(email);
emailProxy.send();
System.out.println("---------------------------------------------------");
emailProxy.receive();
}
}
测试结果:
发送邮件前准备。。。
邮件发送中。。。。。
发送后。。。。。。
-----------------------------------------
接受邮件前准备。。。
邮件接受中..........
接受邮件成功....