代理模式实例分析

昨天下午学习了一个新的模式——代理模式,对于这个最后学习的那个动态代理的例子,由于我们使用了几个从未见过的类和方法,所以当时并不是很理解,相信很多人和我一样,所以晚上回去认真阅读了那个例子,写了下面这段注释和程序流程总结,如果昨天没看明白的同学可以看下,希望对大家能有帮助。

package cn;

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

interface Dog { //定义一个Dog接口,定义两个抽象方法
public void info();

public void run();
}

class GunDog implements Dog { //定义一个GunDog类,实现Dog接口,并且实现Dog接口中的两个方法
public void info() {
System.out.println("小狗");
}

public void run() {
System.out.println("奔跑迅速");
}
}

class LogUtil { //定义一个类LogUtil,该类中的两个方法是我们需要添加的方法
public void method1() {
System.out.println("--------------记录开始---");
}

public void method2() {
System.out.println("--------------记录结果--");
}

}
//定义一个类MyInvocationHandler,实现InvocationHandler接口,用于创建代理实例的调用处理程序
class MyInvokationHandler implements InvocationHandler {

private Object target;//定义一个私有的Object对象target,指向我们需要向其中添加方法的实例

public void setTarget(Object target) {//定义一个方法,将我们需要修改的对象传入到本类对象中
this.target = target;
}
//实现了InvocationHandler中的invoke方法,定义了三个参数,第一个是代理类对象,第二个是方法对象,第三个是方法的参数数组
//即当我们调用proxy对象中的method方法时(该方法的参数为args),将会自动转到下面这个方法进行执行
//相当于每一次执行一个方法时,都会增加两个方法(log中的method1和method2)的执行
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {

LogUtil log = new LogUtil();//创建一个LogUtil类的对象,该对象中有我们需要添加的方法

log.method1();//调用log对象中的方法
Object result = method.invoke(target, args); //调用Method类对象method中的invoke方法,传入参数调用该方法的对象和该方法的参数数组
log.method2();//调用log对象中的方法

return result;//返回method对象方法执行结果(程序中没有使用这个返回值,但是由于是重写方法,我们必须加上这个Object返回值类型)
}

}

class ProxyFactory {//定义一个类,表示代理工厂,在这个类中,实现了动态代理类对象的创建和使用
public static Object getProxy(Object target) { //定义一个静态方法,getProxy,通过getProxy能够得到所需要的Proxy对象
//由于没有写构造器,所以我们不能直接new一个ProxyFactory对象,所以定为静态方法,通过类名直接调用
//参数传进来的是需要修改的对象,也就是我们需要为target对象创建动态代理对象,增加target的功能
MyInvokationHandler handler = new MyInvokationHandler(); //创建MyInvokationHandler对象,创建一个代理实例的调用处理程序
handler.setTarget(target);//将所要修改的对象传入到handler对象中,
//这句话是本程序的关键,通过newProxyInstance能够创建一个代理类实例
//这个方法有三个参数,第一个参数是该代理类实例的类加载器,第二个参数是该实例需要实现的借口,第三个参数为代理类实例指定了一个调用处理程序
//看前两个参数我们不难发现,创建的这个代理类实例和原来的target对象实现自同一个接口,由相同的类加载器加载,说明他们是同一个类型的对象
//通过这个方法,我们返回了一个指定类型对象(target)的代理类实例,当实例调用其中的方法时,将会自动调用处理程序,
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), handler);
}
}

public class Test {
public static void main(String[] args) throws Exception {
Dog target = new GunDog(); //创建一个GunDog类的实例,声明为接口Dog的对象(多态)
Dog d = (Dog) ProxyFactory.getProxy(target);//调用ProxyFactory中的静态方法getProxy,为target对象生成一个代理类实例
//代理类实例造型为Dog接口的对象d
d.info();//调用代理类实例的info方法,由于该代理类实例指向一个调用处理程序(handler),所以程序将会自动执行44行开始的代码
//依次执行 LogUtil log = new LogUtil();log.method1(); Object result = method.invoke(target, args);log.method2();
//相比之间仅仅执行info方法来说多执行了log中的两个方法
d.run();//同上
}
}


/*
* 程序执行过程分析:
* (1)启动JVM后,将所需要的类加载进来,然后从main方法开始执行
* (2)75行创建了一个GunDog类的实例,造型为Dog接口的对象target,等会我们将要为这个对象创建代理对象
* (3)调用ProxyFactory类的静态方法getProxy,传入参数target,程序执行转到59行,然后创建一个”调用处理程序“
* (4)63行程序,将我们需要增加功能的对象(target)传入到”调用处理程序“中,因为在50行中,我们需要通过target对象调用原来的方法method
* (5)程序执行到68行,通过该方法,我们为target对象创建了一个代理实例,作为getProxy方法的返回值返回
* (6)为target对象创建的代理实例在第76行造型为Dog接口的实例d,d就是target的代理实例,该代理实例拥有一个”调用处理程序“(MyInvokationHandler类的对象)
* (7)调用代理实例的info方法,系统将回自动运行代理实例的”调用处理程序“,程序执行到44行的invoke方法
* (8)在47行我们创建了一个LogUtil类对象log,这个对象中有我们需要添加的两个方法(method1和method2),调用log的method1方法
* (9)50行的Object result = method.invoke(target, args);method对象指的就是我们在78行调用的info方法,这个方法的作用相当于执行target.info(args)
* (10)81行调用d的run方法,相当于执行从(7)到(9)行的程序,只是最后执行的是target.run(args)方法
* (11)执行到这,整个程序就已经结束了
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值