----------------------
ASP.Net+Unity开发、
.Net培训、期待与您交流! ----------------------
ShopImpl.java
ShopProxy.java
ShopTest.java
简单的一个静态代理就实现了。重点在于他们都实现了同一个接口,这样才有相同方法,才能在委托类把对象交给代理类的对象的时候确保执行相同方法,实现代理。但在这之余代理可以更自由的去做其他的事情,这就是代理的好处。你随时可以加一个打折促销的广告,夏季冬季随便换也不影响原出售环节。
动态代理
代理是一种设计模式,与现实生活中的代理意思接近。一个类的运行由另一个类去代理运行,这样就可以在目标类的方法运行前后都加入额外的内容去执行,也可以对目标方法的参数进行过滤,委托类与代理类通常存在一个关联。代理设计模式非常有利于程序的管理维护和测试。
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:方法调用时所需要的参数
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 我了解的也不是太多,这里就不多说了,感兴趣的朋友请自行搜索相关资料吧。( ̄▽ ̄)~*
关于 CGLIB 我了解的也不是太多,这里就不多说了,感兴趣的朋友请自行搜索相关资料吧。( ̄▽ ̄)~*
大家互相学习互相进步
----------------------
ASP.Net+Unity开发、
.Net培训、期待与您交流! ----------------------