代理模式的本质:通过增加一定的间接性来完成某些附加的操作。
比如我们通过某个代理来给mm送礼物:
public class testproxy{
publicstatic void main(String args[])
{
schoolgirlmm = new schoolgirl("jiaojiao");
proxypx = new proxy(mm);
px.giveFlower();
px.giveDoll();
px.givePic();
}
}
可观察到在测试主体代码中,并不存在谁送礼物给mm的信息;实际的信息隐藏在proxy中的具体某对象。
class proxy implements igive{
Persuitpm;
publicproxy(schoolgirl mm){
pm= new Persuit(mm);
}
publicvoid giveFlower(){
pm.giveFlower();
}
publicvoid givePic(){
pm.givePic();
}
publicvoid giveDoll(){
pm.giveDoll();
}
}
总体上感觉是绕了下。全部的源代码见src1文件夹。
根据已有的文献资料:
http://blog.youkuaiyun.com/zsx923/article/details/5205138
代理可分为:静态代理和动态代理,那毫无疑问,上述的内容只是静态代理。静态代理的缺点也很明显:每代理一个对象,就需要创建一个新的代理类。
克服静态代理的缺点,动态代理的优点在于:不需要创建代理类。但又能享受代理类的优点。主要依靠java提供proxy代理类来支持。
下面按照如下文档的叙述:
http://langyu.iteye.com/blog/410071
该文档中的相关资料显示:
1. 首先要根据我们的具体类来创建InvocationHandler对象 ;
2. 然后再根据1中创建的handler对象,再与新生成的代理类相关联;
3. 关联完成后,即可以调用。
现在还不想深入其中的细节,但本质上觉得只是把生成代理类的事情,api来自动完成了。具体的测试源代码见src2。
要彻底理解java动态代理,看如下的文档:
http://www.cnblogs.com/flyoung2008/archive/2013/08/11/3251148.html
http://blog.youkuaiyun.com/sunmenggmail/article/details/8545554
Java动态代理类位于Java.lang.reflect包下,一般主要涉及到以下两个类:
(1). Interface InvocationHandler:该接口中仅定义了一个方法Object:invoke(Objectobj,Method method, Object[] args)。在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,如上例中的request(),args为该方法的参数数组。这个抽象方法在代理类中动态实现。
(2).Proxy:该类即为动态代理类,作用类似于上例中的ProxySubject,其中主要包含以下内容:
Protected Proxy(InvocationHandlerh):构造函数,估计用于给内部的h赋值。StaticClass getProxyClass (ClassLoader loader, Class[] interfaces):获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。
Static Object newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)。
形象的来讲,就是通过Proxy.newProxyInstance生成一个代理类的对象,然后,对这个对象的所有方法的调用,都会自动的调用invoke函数,对原有函数的追踪或是统计开销,都可以在invoke函数中实现。在使用动态代理类时,我们必须实现InvocationHandler接口。
下面来写个实例,验证对于代理对象的任何方法的调用,最终都会触发invoke函数;开始之前,想想必要的关键点:
1. 要继承的那个接口的名字:InvocationHandler;
2. Invoke方法的原型:public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
3. return method.invoke(proxied, args);
4. }
4. 创建代理类的基本语法:Proxy.newProxyInstance(Interface.class.getClassLoader(), new Class[]{Interface.class}, new DynamicProxyHandle(real));
掌握上述的基本技术点后,再来我们的实验,从用例入手:
假设被代理的类中拥有两个方法:
actFirst();
actSecond();
然后生成代理类后,比如生成的代理类是:daili
daili.actFirst();
daili.actSecond();
查看上述两者的调用路径是如何的?
拥有上述信息后,如何完成相关的设计?
Public interfaceService{
Public void doFirst;
Public void doSecond;
}
Public MyServcieimplements Service{
Public void doFirst(){
System.out.println(“I am thefirst”)
}
Public void doSecond(){
System.out.println(“I am thesecond”);
}
}
定义自己的InvocationHandler:
Public class MyHandlerimplements InvocationHandler{
//invoke方法的原型:
Public Object invoke(Object proxy, Method method, Object[] args)throws Throwable{
return method.invoke(myservice, args);
}
}
下面开始测试动态代理的主类:
publicclass myproxy{
//首先创建我们的service类,然后再以该类为模板创建代理类?
MyService ms = new MyService();
Object daili = proxy.newProxyInstance(Service.class.getClassLoader(), new Class[]{Service.class}, new MyHandle());
Daili.doFirst();
Daili.doSecond();
}
实现过程中遇到的问题:
1. 居然连interface中的方法该怎么定义都不确定;
方法的定义只要到”()”即可,不需要有”{”;
importjava.lang.reflect.*;
interfaceService{
public void doFirst();
public void doSecond();
}
classMyService implements Service{
public void doFirst(){
System.out.println("I amthe first");
}
public void doSecond(){
System.out.println("Iam the second");
}
}
//定义自己的InvocationHandler:
classMyHandler implements InvocationHandler{
//invoke方法的原型:
private MyService myservice;
public MyHandler(MyService ms){
myservice = ms;
}
public Object invoke(Object proxy,Method method, Object[] args) throws Throwable{
if(method.getName().equals("doSecond"))
returnmethod.invoke(myservice, args); //方法需要来自某个特定的类;
return null;
}
}
//下面开始测试动态代理的主类:
publicclass myproxy{
public static void main(String args[])
{
//首先创建我们的service类,然后再以该类为模板创建代理类?
MyService ms = newMyService();
Service daili =(Service)Proxy.newProxyInstance
(Service.class.getClassLoader(),new Class[]{Service.class}, new MyHandler(ms));
daili.doFirst();
daili.doSecond();
}
}
如上的实例代码,无论daili调用什么方法,MyHandler中的invoke方法都会被调用;
通过这么绕一圈,增加代码执行过程中的间接性,可以在此中间性中做很多的处理。