您的位置:首页 > 职场人生

黑马程序员 学习日记(十)

2014-07-19 17:30 169 查看
----------------------
ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------

动态代理

代理是一种设计模式,与现实生活中的代理意思接近。一个类的运行由另一个类去代理运行,这样就可以在目标类的方法运行前后都加入额外的内容去执行,也可以对目标方法的参数进行过滤,委托类与代理类通常存在一个关联。代理设计模式非常有利于程序的管理维护和测试。

1.静态代理

shop.java
package com.itheima.proxy;
/**
* 定义一个商店接口
* 无论是原商场还是代理商都要实现这个接口
* @author cloud
*
*/
public interface Shop {
public void sale() ;   //卖东西
public void stoke() ;  //进货
}

ShopImpl.java
package com.itheima.proxy;
/**
* 原商店
* 有出售和进货能力
* @author cloud
*
*/
public class ShopImpl implements Shop {

@Override
public void sale() {
System.out.println("卖出一件货物。");
}

@Override
public void stoke() {
System.out.println("采购一批货物");
}

}

ShopProxy.java
package com.itheima.proxy;
/**
* 代理类
* 代理出售和进货
* @author cloud
*
*/
public class ShopProxy implements Shop {
private ShopImpl shopImpl ;
public ShopProxy(ShopImpl shopImpl){
this.shopImpl = shopImpl ;
}
@Override
public void sale() {
System.out.println("出售货物之前");
shopImpl.sale();
System.out.println("出售货物之后");
}

@Override
public void stoke() {
System.out.println("进货之前");
shopImpl.stoke();
System.out.println("进货之后");
}

}

ShopTest.java
package com.itheima.proxy;
/**
* 测试
* @author cloud
*
*/
public class ShopTest {
public static void main(String[] args){
ShopImpl shopImpl = new ShopImpl() ;
ShopProxy shopProxy = new ShopProxy(shopImpl) ;  //把对象交给代理对象
shopProxy.sale();     //代理对象在卖东西
shopProxy.stoke();  //代理对象 在进货
}
}

简单的一个静态代理就实现了。重点在于他们都实现了同一个接口,这样才有相同方法,才能在委托类把对象交给代理类的对象的时候确保执行相同方法,实现代理。但在这之余代理可以更自由的去做其他的事情,这就是代理的好处。你随时可以加一个打折促销的广告,夏季冬季随便换也不影响原出售环节。

2.动态代理

但在实际开发中,如果只使用程序员预订编辑好的代理类,每一个接口每一个委托类都要去设计一个代理类,这样做徒然增加工作量,维护起来也很费时费力。最好就是一个代理类能接受所有委托。利用Java的反射机制设计一个代理类使其接受任意代理。
要做这样一个代理,那我们就要仔细思考。首先肯定还是要接收一个对象参数,然后要实现此对象的哪个方法,执行方法可能需要参数。这样就一共需要这三个参数。JDK正好为我们提供了一个接口,
InvocationHandler接口: 
public interface InvocationHandler { 
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable; 



参数说明: 
Object proxy:指被代理的对象。 

Method method:要调用的方法 

Object[] args:方法调用时所需要的参数 

接口解决了,那么最关键的类呢?关键就在于这个类必须是动态的,如果写死它最终还是一个静态代理。所以这个类必须要在运行时动态创建。实现动态创建类要使用Proxy类。
把上面的代理类稍微改动一下,接口和委托类不用动。
package com.itheima.proxy;

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

/**
* 代理类
* 代理出售和进货
* @author cloud
*
*/
public class ShopProxy implements InvocationHandler {
private Object target ;

public Object bind(ShopImpl target){
this.target = target ;

return Proxy.newProxyInstance(target.getClass().getClassLoader(),  //通过反射创建一个类
target.getClass().getInterfaces(), this) ;
}

//代理对象执行任意方法都会自动来执行一次这个方法。
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result = null ;
System.out.println("start");
result = method.invoke(target, args) ;    //执行委托方法
System.out.println("end");
return result;
}

}
main方法中也稍微改改,使用方式有所变化
package com.itheima.proxy;
/**
* 测试
* @author cloud
*
*/
public class ShopTest {
public static void main(String[] args){
ShopProxy proxy = new ShopProxy() ;  //获得代理类
Shop shop = (Shop)proxy.bind(new ShopImpl()) ;   通过接口把委托对象与代理对象绑定
shop.sale();
}
}
所以,bind()方法里传什么对象都可以了,当然前提还是实现了相同接口才行。如果你不了解反射是很难理解动态的代理过程的,不懂的同学请补习一下。。。

总结

可以看出JDK的代理方式必须依赖接口,如果一个类没有实现相应接口是不可以被代理的。
如果你想既不实现接口又要代理,建议去了解一下CGLIB,CGLIB是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。

关于CGLIB我了解的也不是太多,这里就不多说了,感兴趣的朋友请自行搜索相关资料吧。( ̄▽ ̄)~*
大家互相学习互相进步
----------------------
ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: