设计模式专题(三)代理模式

代理模式引入

作用:

  • aop实现
  • 拦截器
  • 解耦
  • 专人做专事,自己不想做但是又不得不做的事

概念: 代理角色、被代理的角色(目标对象),由被代理角色来做最终的决定
代理角色通常来说会持有被代理角色对象引用(以便于代理角色完成工作之前或者之后能够找到被代理对象,能够通知被代理对象)

代理模式分类

  • 静态代理
  • 动态代理

设计模式专题(三)代理模式_第1张图片

静态代理实现

静态代理的类比较固定,必须业务已知才行,这也是静态代理最大的弊端。
首先做一个接口:

public interface Person {

    public void findLove();

    public void zufangzi();

    public void buy();

    public void findJob();

    //......
}

然后来一个实现类(儿子要结婚):

public class Son implements Person{

    public void findLove(){
        //我没有时间
        //工作忙
        System.out.println("找对象,肤白貌美大长腿");
    }

    public void zufangzi() {}

    public void buy() {}

    public void findJob() {}
}

这个实现类可能需要很多方法被代理,以findLove为例,我们做一个代理类:

public class Father {

    private Person person;

    //没办法扩展
    public Father(Person person){
        this.person = person;
    }

    //目标对象的引用给拿到
    public void findLove(){
        System.out.println("根据你的要求物色");
        this.person.findLove();
        System.out.println("双方父母是不是同意");
    }

}

来测试一下:

public static void main(String[] args) {

    Father father = new Father(new Son());

    father.findLove();

}

动态代理实现

jdk代理实现

我们说jdk动态代理需要代理对象实现接口才可以,所以,我们实现一下刚才静态代理的person类

public class XieMu implements Person{

   public void findLove(){
       System.out.println("高富帅");
       System.out.println("身高180cm");
       System.out.println("胸大,6块腹肌");

   }

   public void zufangzi() {
       System.out.println("租房子");
   }

   public void buy() {
       System.out.println("买东西");
   }

   public void findJob() {
       System.out.println("月薪20K-50k");
       System.out.println("找工作");
   }
}

比如,谢幕这个人要求代理找对象

public class JDKMeipo implements InvocationHandler{
    //被代理的对象,把引用给保存下来
    private Person target;

    public Object getInstance(Person target) throws Exception{
        this.target = target;

       Class clazz = target.getClass();

        //字节码是如何重组的?
        //用来生成一个新的对象(字节码重组来实现)
        return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
    }


    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        System.out.println("我是媒婆:我要给你找对象,现在已经拿到你的需求");
        System.out.println("开始物色");

        method.invoke(this.target,args);

        System.out.println("如果合适的话,就准备办事");

        return  null;
    }
}

比如,谢幕这个人要求代理找工作

public class JDK58 implements InvocationHandler{
    //被代理的对象,把引用给保存下来
    private Person target;

    public Object getInstance(Person target) throws Exception{
        this.target = target;

       Class clazz = target.getClass();

        //字节码是如何重组的?
        //用来生成一个新的对象(字节码重组来实现)
        return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        System.out.println("我是58:我要给你找工作,现在已经拿到你的简历");
        System.out.println("开始投递");

        method.invoke(this.target,args);

        System.out.println("安排面试");

        return  null;
    }
}

我们来测试一下:

public class JDKProxyTest {

    public static void main(String[] args) {

        try {
            Person obj = (Person)new JDK58().getInstance(new XieMu());
            System.out.println(obj.getClass());
            obj.findJob();

            //JDK中有个规范,只要要是$开头的一般都是自动生成的

            //通过反编译工具可以查看源代码
            //byte [] bytes = ProxyGenerator.generateProxyClass("$Proxy0",new Class[]{Person.class});
            //FileOutputStream os = new FileOutputStream("E://$Proxy0.class");
            //os.write(bytes);
            //os.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

jdk动态代理的原理

字节码重组:

  1. 拿到被代理对象的引用,并且获取到它的所有的接口,反射获取
  2. JDK Proxy类重新生成一个新的类、同时新的类要实现被代理类所有实现的所有的接口
  3. 动态生成Java代码,把新加的业务逻辑方法由一定的逻辑代码去调用(在代码中体现)
  4. 编译新生成的Java代码.class
  5. 再重新加载到JVM中运行

cglib代理实现

首先来一个需要代理的类,不需要实现接口

public class ZhangSan {

   public void findLove(){
       System.out.println("肤白貌美大象腿");
   }

}

然后,媒婆帮忙张三代理:

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();

   }


   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;
   }
}

测试一下:   

public static void main(String[] args) {

        try {
            ZhangSan obj = (ZhangSan)new CglibMeipo().getInstance(ZhangSan.class);
            obj.findLove();
            System.out.println("--------------------------------");
           // System.out.println(obj.getClass());
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

 

你可能感兴趣的:(Java架构)