代理模式(Proxy Pattern),23种java经常使用设计模式之一。代理模式的定义:代理类对被代理对象提供一种代理以控制对这个对象的访问。代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及过后处理消息等。我的理解:在生活中咱们经常把没必要要的事情丢给别人去完成,而这些没必要要的部分至关于他们代替咱们完成的,这就至关因而代理模式。java
例如:设计模式
一、明星与经纪人:就假设在和甲方谈商演的时候,影视明星只负责决定是否去演出,而经纪人就须要先去联系甲方并和甲方商定角色和报酬,而后将结果告诉影视明星,影视明星决定是否去演出,经纪人在获得明星的答复后将结果通知甲方,走后面的流程。框架
二、中介与房东:在房屋租(售)的时候,租(购)房人会先找中介咨询房屋信息,若是中介有钥匙还能够带租(购)房人去看房,若是租(购)房人对房屋无购买意愿,则本次流程结束;若是租(购)房人对房屋有兴趣,则先与中介协商价格;若是中介以为房东不会接受这个价格,则直接拒绝;若是中介以为价格合理,则与房东沟通,中介将房东的决定告知租(购)房人,而后走接下来的流程。maven
一、当须要控制对一个对象的访问,为不一样用户提供不一样级别的访问权限时可使用保护代理模式。ide
二、当客户端对象须要访问远程主机中的对象时可使用远程代理模式,如RPC。性能
三、当须要为一个对象的访问(引用)提供一些额外的操做时可使用代理模式。测试
四、当须要用一个消耗资源较少的对象来表明一个消耗资源较多的对象,从而下降系统开销、缩短运行时间时可使用虚拟代理,例如一个对象须要很长时间才能完成加载时。(待论证)this
五、当须要为某一个被频繁访问的操做结果提供一个临时存储空间,以供多个客户端共享访问这些结果时可使用缓冲代理。经过使用缓冲代理,系统无须在客户端每一次访问时都从新执行操做,只需直接从临时缓冲区获取操做结果便可。(待论证)设计
静态代理要求代理类必须继承被代理对象的接口。至关于中介(代理类)知道房东(被代理对象)有哪几个方面的要求(方法)。代理
代码实现
房东接口
public interface ILandlord { //出售 String sell(int price); //出租 String lease(int leaseTime,int price); }
房东实现类
public class Landlord implements ILandlord { String houseName;//房屋名称 int houseSellPrice;//房屋出售价格 int houseLeasePrice;//房屋出租价格(单价) int houseLeaseTime;//最短出租时间 @Override public String sell(int price) { if(price>=houseSellPrice){ return "我赞成以"+price+"元的价格出售"+houseName; }else{ return "我不一样意以"+price+"元的价格出售"+houseName; } } @Override public String lease(int leaseTime, int price) { if(price<houseLeasePrice){ return "我不一样意以"+price+"元的价格将"+houseName+"出租"; } if(leaseTime<houseLeaseTime){ return "我不一样意将"+houseName+"出租"+leaseTime+"个月"; } return "我赞成以"+price+"元的价格将"+houseName+"出租"+leaseTime+"个月"; } public Landlord() { } public Landlord(String houseName, int houseSellPrice, int houseLeasePrice, int houseLeaseTime) { this.houseName = houseName; this.houseSellPrice = houseSellPrice; this.houseLeasePrice = houseLeasePrice; this.houseLeaseTime = houseLeaseTime; } public String getHouseName() { return houseName; } public void setHouseName(String houseName) { this.houseName = houseName; } public int getHouseSellPrice() { return houseSellPrice; } public void setHouseSellPrice(int houseSellPrice) { this.houseSellPrice = houseSellPrice; } public int getHouseLeasePrice() { return houseLeasePrice; } public void setHouseLeasePrice(int houseLeasePrice) { this.houseLeasePrice = houseLeasePrice; } public int getHouseLeaseTime() { return houseLeaseTime; } public void setHouseLeaseTime(int houseLeaseTime) { this.houseLeaseTime = houseLeaseTime; } }
中介类
public class Intermediary implements ILandlord { private ILandlord obj; Intermediary(ILandlord obj){ super(); this.obj=obj; } @Override public String sell(int price) { System.out.println("中介将购房人的出价告知房东"); String res = obj.sell(price); System.out.println("房东:"+res); System.out.println("中介将房东的结果告知购房人"); return "房东:"+res; } @Override public String lease(int leaseTime, int price) { System.out.println("中介将租房人的出价告知房东"); String res = obj.lease(leaseTime,price); System.out.println("房东:"+res); System.out.println("中介将房东的结果告知租房人"); return "房东:"+res; } }
测试类
public class StaticProxyTest { public static void main(String[] args) { Landlord landlordA=new Landlord("保利001号",3000000,2000,6); Intermediary proxy=new Intermediary(landlordA); String res = proxy.sell(3010000); System.out.println("购房者获得的结果:"+res); res = proxy.lease(5,1998); System.out.println("购房者获得的结果:"+res); } }
结果
中介将购房人的出价告知房东 房东:我赞成以3010000元的价格出售保利001号 中介将房东的结果告知购房人 购房者获得的结果:房东:我赞成以3010000元的价格出售保利001号 中介将租房人的出价告知房东 房东:我不一样意以1998元的价格将保利001号出租 中介将房东的结果告知租房人 购房者获得的结果:房东:我不一样意以1998元的价格将保利001号出租
JDK中的动态代理是在程序运行期间由JVM根据反射等机制动态的生成,因此不存在代理类的字节码文件。代理类和委托类的关系是在程序运行时肯定。JDK中的动态代理使用的是java.lang.reflect.Proxy中的newProxyInstance方法来实现。
newProxyInstance方法的三个参数是ClassLoader loader、Class<?>[] interfaces和InvocationHandler h。ClassLoader loader:类加载器,负责将类的字节码装载到 Java 虚拟机(JVM)中并为其定义类对象,而后该类才能被使用。Proxy 静态方法生成动态代理类一样须要经过类装载器来进行装载才能使用。
Class<?>[] interfaces:指明被代理类实现的接口,以后咱们经过拼接字节码生成的类才能知道调用哪些方法。
InvocationHandler h:这是一个方法委托接口,每一个代理的实例都有一个与之关联的 InvocationHandler 实现类,若是代理的方法被调用,那么代理便会通知和转发给内部的 InvocationHandler 实现类,由它的invoke方法决定处理。InvocationHandler 接口内部只是一个 invoke() 方法。
invoke方法的三个参数是Object proxy、 Method method和 Object[] args。
Object proxy:代理类实例。注意:这个代理类实例不是代理接口的实现类对象,而是JDK根据传入的接口生成一个extends Proxy implements Interface的代理类的对象。这个对象其实就是Proxy.newProxyInstance方法生成的对象(结尾处作验证)。
Method method:被调用的方法对象。
Object[] args:传入的方法参数。
待代理的接口
public interface Star { /** * 唱歌 * @param song * @return */ String sing(String song); /** * 演戏 * @return */ String acting(); }
接口的实现类
/** * 歌星 */ public class SingingStar implements Star { @Override public String sing(String song) { System.out.println("明星本人表示愿意唱:《"+song+"》"); return "愿意唱:《"+song+"》"; } @Override public String acting() { System.out.println("明星本人表示不肯意演戏"); return "不肯意演戏"; } }
InvocationHandler接口实现类
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class DynamicsStarProxy implements InvocationHandler { Object obj; DynamicsStarProxy(Object obj){ this.obj=obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("动态明星代理和甲方协商出演的酬劳"); Object res = method.invoke(obj, args); System.out.println("动态明星代理获得明星的决定,并告知甲方"); return res; } }
测试类
public class DynamicsProxyTest { public static void main(String[] args) { Star taylorSwift=new SingingStar(); DynamicsStarProxy starProxy=new DynamicsStarProxy(taylorSwift); Star proxy= (Star) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),taylorSwift.getClass().getInterfaces(),starProxy); //甲方找霉霉演唱Mean String singRes=proxy.sing("Mean"); System.out.println("甲方获得的结果:"+singRes); //甲方又想找霉霉演戏 String actRes=proxy.acting(); System.out.println("甲方获得的结果:"+actRes); } }
结果
动态明星代理和甲方协商出演的酬劳 明星本人表示愿意唱:《Mean》 动态明星代理获得明星的决定,并告知甲方 甲方获得的结果:愿意唱:《Mean》 动态明星代理和甲方协商出演的酬劳 明星本表示不肯意演戏 动态明星代理获得明星的决定,并告知甲方 甲方获得的结果:不肯意演戏
Cglib是一个强大的,高性能,高质量的代码生成类库。它能够在运行期扩展JAVA类与实现JAVA接口。其底层实现是经过ASM字节码处理框架来转换字节码并生成新的类。CGLIB包的底层是经过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类,大部分功能其实是ASM所提供的,Cglib只是封装了ASM,简化了ASM操做。GLib动态代理不要求被代理类实现接口,任何一个类均可以被轻松的代理(final类不能,final方法也不能)。
Cglib动态代理须要自定义实现MethodInterceptor接口,在代理对象调用方法时,会被拦截到intercept方法中。public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)
Object obj:cglib生成的代理对象,对应JDK动态代理中invoke方法的Object proxy。
Method method:被调用的代理对象方法,对应JDK动态代理中invoke方法的Method method。
Object[] args:方法入参,对应JDK动态代理中invoke方法的Object[] args。
MethodProxy proxy:被调用的方法的代理方法,CGLib动态代理经过该参数的invokeSuper方法来调用被代理对象的方法。
代码实现
maven依赖
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version> </dependency>
待代理的类
/** * 舞蹈名星 */ public class DanceStar { private String name;//艺名 //跳舞方法 public String dancing(String typeName){ System.out.println(name+"表示愿意跳"+typeName); return name+"愿意跳"+typeName; } public String getName() { return name; } public void setName(String name) { this.name = name; } DanceStar(){ super(); } DanceStar(String name){ super(); this.name=name; } }
Cglib代理类
import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class CglibStarProxy implements MethodInterceptor { /** * 自定义方法:利用Enhancer类生成代理类 * @param clazz * @param <T> * @return */ public <T> T getObjByEnhancer(Class<T> clazz){ Enhancer enhancer=new Enhancer(); enhancer.setSuperclass(clazz); enhancer.setCallback(this); T res = (T) enhancer.create(); return res; } /** * 自定义方法:利用Enhancer类生成代理类(模拟JDK代理的用法) * @param target * @return */ private Object object; public Object getObjByEnhancer(Object target){ this.object=target; Enhancer enhancer=new Enhancer(); enhancer.setSuperclass(target.getClass()); enhancer.setCallback(this); Object res = enhancer.create(); return res; } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("Cglib动态明星代理和甲方协商出演的酬劳"); Object res=null; res = proxy.invokeSuper(obj,args); //res = method.invoke(object, args);//模拟JDK代理的用法 System.out.println("Cglib动态明星代理获得明星的决定,并告知甲方"); return res; } }
测试类
public class CglibStarProxyTest { public static void main(String[] args) { CglibStarProxy starProxy=new CglibStarProxy(); //DanceStar ssyy=new DanceStar("三上悠亚");//模拟JDK动态代理 DanceStar ssyy2=null; ssyy2 = starProxy.getObjByEnhancer(DanceStar.class); //ssyy2= (DanceStar) starProxy.getObjByEnhancer(ssyy);//模拟JDK动态代理 String res=ssyy2.dancing("钢管舞"); System.out.println("甲方获得的结果:"+res); } }
静态代理:是经过静态代理类实现了被代理类的接口的方式来实现的。
JDK动态代理:是经过JVM根据反射等机制动态的生成一个被代理类的接口的实现类实现的,该实现类的继承方法会调用代理类中的invoke方法。
private MyInvocationHandler h; m3 = Class.forName("com.***.Star").getMethod("sing", new Class[] { Class.forName("java.lang.String") }); public final void sing(Sting song) { try { this.h.invoke(this, m3, new Object[] {song}); return; } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } }
CGLib动态代理:是使用ASM来生成被代理类的一个子类的字节码,该子类会重写父类的方法,在方法中调用代理类对象中的intercept()方法。
public final String dancing(String paramString) { MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0; if (tmp4_1 == null) { tmp4_1; CGLIB$BIND_CALLBACKS(this); } MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0; if (tmp17_14 != null) { return (String)tmp17_14.intercept(this, CGLIB$dancing$2$Method, new Object[] { paramString }, CGLIB$dancing$2$Proxy); } return super.dancing(paramString); }
接口
public interface Star { /** * 唱歌 * @param song 此处用对象封装,能够将代理生成的对象传入 * @return */ Object sing(Object song); }
实现类
/** * 歌星 */ public class SingingStar implements Star { @Override public Object sing(Object song) { return song; } }
代理类
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class DynamicsStarProxy implements InvocationHandler { Object obj; DynamicsStarProxy(Object obj){ this.obj=obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if("sing".equals(method.getName())){//判断是否为sing方法 for(Object o:args){//sing方法c传入的就是代理生成的对象 System.out.println(proxy==o);//判断地址是否相同 } } Object res = method.invoke(obj, args); return res; } }
测试类
import java.lang.reflect.Proxy; public class DynamicsProxyTest { public static void main(String[] args) { Star taylorSwift=new SingingStar(); DynamicsStarProxy starProxy=new DynamicsStarProxy(taylorSwift); Star proxy= (Star) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),taylorSwift.getClass().getInterfaces(),starProxy); Object singRes=proxy.sing(proxy); } }
结果
true
感谢你看到这里,文章有什么不足还请指正,以为文章对你有帮助的话记得给我点个赞,天天都会分享java相关技术文章或行业资讯,欢迎你们关注和转发文章!