java署理模式学习
需求
主人公frade 刚刚来到北京,马上就要开启自己的北漂生活了,首先解决的问题就是需要找房子,那么问题来了,北京的房子如果你想找房东去租,难度太大,比较容易的办法就是找中介。这里咋们用proxy模式来实现下这个需求。
proxy模式分为两种:静态代理和动态代理,以下是两种方式分别实现上面的需求;
静态代理
1. 抽象角色
按照java面向对象的思路首先定义一个person的接口。
public interface Person { /** * 这里有两个参数,用来设置目标房源的需求 * @param roomcount 房间个数 * @param roomCharge 房租总金额 */ void findHouse( int roomcount,int roomCharge ); }
2. 创建真实角色
public class Frade implements Person { @Override public void findHouse( int rommcount , int roomCharge) { System.out.println("我最近想找个房子,开启自己的北漂生活"); System.out.println( "我想找个" + rommcount + "居室" ); System.out.println("房子租金不超过" + roomCharge + "元"); } }
3.创建中介代理对象,以链家为例
public class HomeLike implements Person { private Person person; public HomeLike (Person person){ this.person = person; } @Override public void findHouse( int roomcount, int roomCharge ) { System.out.println("我是链家工作人员小张,现在开始给你找符合你要求的房子"); System.out.println("我将给你寻找附近符合要求的"+ roomcount +"居室"); System.out.println("并且一居室的金额不超过"+ roomCharge +"元"); person.findHouse( roomcount,roomCharge ); System.out.println("找房子结束"); } }
总结 :
1.抽象主角色,可以是接口,也可以是抽象类;
2.真实主题角色: 业务逻辑的执行者;
3.代理主题角色:内部含有真实角色的引用,负责其真实角色的调用,并在真实角色前后做预期的处理和善后的工作。
静态代理的缺点:
1.代理对象的一个接口只能服务于一个对象,如果代理的方法很多,势必要每一个方法都进行代理。
2.如果接口进行扩展,除了实现类实现这个方法外,代理类也需要实现这个方法。
动态代理:
本文动态代理还是沿用上面的例子,只对代理类方式进行修改。
使用JDK 完成动态代理
public class HomeLink implements InvocationHandler{ private Person person; public Person getInstance( Person person ) { this.person = person; ClassLoader classLoader = person.getClass().getClassLoader(); return (Person) Proxy.newProxyInstance( classLoader, person.getClass().getInterfaces(), this ); } @Override public Object invoke( Object proxy, Method method, Object[] args ) throws Throwable { System.out.println("我是链家工作人员小张,现在开始给你找符合你要求的房子"); for ( int i = 0; i < args.length; i++ ) { Object arg = args[i]; if ( i == 0 ) { System.out.println("我将给你寻找附近符合要求的"+ arg +"居室"); } if( i ==1 ){ System.out.println("并且一居室的金额不超过"+ arg +"元"); } } method.invoke( this.person, args ); System.out.println("找房子结束"); return null; } }
动态代理类的实现步骤:
1.拿到代理对象的引用,并且获取到它所有的接口,利用反射获取;
2. 用JDK 的 proxy类重新生成一个新的类。同时,类要实现被代理类的所有接口
3.动态生成java代码,把新添加的业务逻辑方法由一定的逻辑代码去调用(在生成的代码中体现)
4.重现编译java文件,生产class文件
5.将生成的class文件加载到JVM中
6.类实例化
//以上的这个过程叫做字节码重组。JDK中有一个规范,凡是以$开都的类都是自动生成的。
cglib 实现动态代理
以业务员小张为例子, 小张没次带客户出来看房时,都需要在公司记录看房子的经过,这个记录有专门的人负责进行登记,下面就用cglib来完成这个流程。
1. 对小张进行抽象
public class XiaoZhang { public void findHouse(){ System.out.println("我是根据客户的条件给客户进行找房子"); } }
2. 完成外出工作记录抽象
public class CglibMeipo implements MethodInterceptor{ public Object getInstance(Class<?> clazz) throws Exception{ Enhancer enhancer = new Enhancer(); //要把哪个设置为即将生成的新类父类 enhancer.setSuperclass(clazz); enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { //对业务员看房记录做登记 System.out.println("记录外出日期,所带客户资料"); System.out.println("客户看房需求"); methodProxy.invokeSuper(o,objects); System.out.println("看房结束,会去进行报道"); return null; } }
3.测试
public class CglibTest { public static void main(String[] args) { try { XiaoZhang obj = (XiaoZhang )new CglibMeipo().getInstance(XiaoZhang .class); obj.findLove(); System.out.println("--------------------------------"); // System.out.println(obj.getClass()); } catch (Exception e) { e.printStackTrace(); } } }
cglib 和jdk 动态代理的区别 ,jdk动态代理在生成类时,用户必须实现接口,如果没有实现接口,无法动态生成,cglib完美的解决了这个痛点,当用户不能继承接口时,可以用cglib进行动态生成。