java署理模式学习

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进行动态生成。