天天看点

Java学习笔记-代理

代理,是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象。这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。

这里用到一个编程思想:不要随意去修改别人已经写好的代码或者方法,如果需要修改,可以通过代理的方式去扩展该方法。

代理模式的关键点在于:代理对象和目标对象。代理对象是对目标对象的扩展,并且会调用目标对象。

1.静态代理

静态代理在使用时,需要定义接口或者父类,目标对象与代理对象一起实现相同的接口或者是继承相同的父类。

下面举个案例来解释:

模拟保存动作,定义一个保存动作的接口:Save

package proxy;

public interface Save {
	public void save();
}
           

然后目标对象实现这个接口:Saver

package proxy;

public class Saver implements Save {
	public void save(){
		System.out.println("---完成存储任务!---");
	}
}

           

此时使用静态代理方式:

即通过调用目标对象的方式实现代理对象的实现。

package proxy;

public class SaverProxy implements Save{
	private Saver s;
	public SaverProxy(Saver s){
		this.s=s;
	}
	public void save(){
		System.out.println("---系统正在加载中---");
		s.save();
		System.out.println("---系统加载完成---");
	}
}
           

最后,是实验类:

package proxy;

public class Test {
	public static void main(String[] args){
		Saver s=new Saver();
		SaverProxy sp=new SaverProxy(s);
		sp.save();
	}
}
           

实验结果:

---系统正在加载中---
---完成存储任务!---
---系统加载完成---
           

由此可见,静态代理可以做到在不修改目标对象的功能前提下,对目标进行功能扩展。当然,缺点也显而易见,因为代理对象需要与目标对象实现同样的接口,所以会有很多代理类,类太多。同时,一旦接口增加方法,目标对象和代理对象都要进行维护。

如何解决静态代理中的缺点呢?答案是可以使用动态代理方式。

2.动态代理

动态代理由以下特点:

1.代理对象只能代理接口

2.代理对象的生成,是利用JDK的API,动态地在内存中构建代理对象

JDK中生成代理对象的API

代理类所在包:java.lang.reflect.Proxy

JDK实现代理只需使用newProxyInstance方法,但是该方法需要接收三个参数:

------首先是指定当前目标对象使用的类加载器,获取加载器的方法是固定的,目前,用null表示使用默认的类加载器。

2.一个Class对象数组,其中每个元素都是需要实现的接口类型。

3.一个调用处理器。

动态调用过程如下图所示:

Java学习笔记-代理

我们举一个简单的例子:

目标接口:

package proxy;

public interface Subject{
	public void rent();
	public void hello(String str);
}
           

目标接口的实现类:

package proxy;

public class RealSubject implements Subject{//原对象
	public void rent() {
		System.out.println("原对象的rent函数主体");
	}
	public void hello(String str) {
		System.out.println("原对象的hello函数主体:hello"+str);
	}
}
           

调用处理器的实例化:

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

public class DynamicProxy implements InvocationHandler{//调用处理器类,用于调用原对象
	private Object subject;
	public DynamicProxy(Object subject){
		this.subject=subject;
	}
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		// TODO Auto-generated method stub
		if("rent".equals(method.getName())){
			System.out.println("before rent house");
	        System.out.println("Method:" + method);
	        method.invoke(subject, args);
	        System.out.println("rent over");
		}else if("hello".equals(method.getName())){
			System.out.println("before ");
	        System.out.println("Method:" + method);
	        method.invoke(subject, args);
	        System.out.println("hello over");
		}
		return null;
	}	
}
           

动态生成类对象的过程:

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

public class Client{
	public static void main(String[] args){
		Subject realSubject=new RealSubject();
		InvocationHandler handler=new DynamicProxy(realSubject);
		Subject subject=(Subject)Proxy.newProxyInstance(realSubject.getClass().getClassLoader(), realSubject.getClass().getInterfaces(), handler);
		//动态生成类对象,由于Java是单继承语言,且生成的类对象已经默认继承Proxy类,所以只能根据接口进行代理
		System.out.println(subject.getClass().getName());
        subject.rent();
        subject.hello("world");
	}
}