设计模式之代理模式

学习目标

1,掌握代理模式的应用场景和实现原理

2,了解静态代理模式和动态代理模式的区别

3,了解CGLib和JDK Proxy的根本区别

4,手写实现定义的动态代理

代理模式定义

代理模式(Proxy Pattern)是指为其他对象提供一种代理,以控制对这个对象的访问。

代理对象在客户端跟目标对象之间起到中介作用,属于结构型设计模式。

生活中的代理模式

房产中介

快递小哥

黄牛党

媒婆

代理模式实现方式

方式一:静态代理

按照农村找对象类举例子。

新建一个person.java类

package com.packer.partten.factory.proxy.staticproxy;

/**
 * Created by lijianfang on 2021/9/25.
 */
public interface Person {

    public void findLove();
}

新建一个Son.java类,实现person类中的找对象要求

package com.packer.partten.factory.proxy.staticproxy;

/**
 * Created by lijianfang on 2021/9/25.
 */
public class Son implements Person{
    /**
     * 找对象的要求:肤白貌美大长腿
     */
    public void findLove(){
        System.out.println("找对象的要求:肤白貌美大长腿");
    }

}

再新建一个Father.java类

package com.packer.partten.factory.proxy.staticproxy;

/**
 * Created by lijianfang on 2021/9/25.
 */
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("双方父母同意");
    }
}

最后做一下测试

package com.packer.partten.factory.proxy.staticproxy;

/**
 * Created by lijianfang on 2021/9/25.
 */
public class FatherProxyTest {

    public static void main(String[] args) {
        Father father = new Father((Person) new Son());
        father.findLove();
    }
}

测试结果如下:儿子通过父亲的代理找到对象。

父亲为儿子物色对象
找对象的要求:肤白貌美大长腿
双方父母同意

Process finished with exit code 0

第二种方式:动态代理模式

动态代理方式一:CGLib动态代理是通过生成一个被代理对象的子类,然后重写父类的方法。

小明通过媒婆找对象。先新建一个xiaoming.java类

package com.packer.partten.factory.proxy.cglib;

/**
 * Created by lijianfang on 2021/9/27.
 */
public class xiaoming {
    /**
     * 找对象的要求:肤白貌美大长腿
     */
    public void findLove(){
        System.out.println("找对象的要求:肤白貌美大长腿");
    }
}

再新建一个媒婆类Meipo.java类

package com.packer.partten.factory.proxy.cglib;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * Created by lijianfang on 2021/9/27.
 */
public class Meipo implements MethodInterceptor{

    public Object getInstance(Class clazz) throws Exception{
        Enhancer enhancer = new Enhancer();
        //把父类设置为谁,这一步就是告诉cglib,生成的字类需要继承那个类
        enhancer.setSuperclass(clazz);
        //设置回调
        enhancer.setCallback(this);
        //第一步/生成源代码
        //第二不 编译class文件
        //第三步 加载到JVM中,并返回被代理的对象
        return enhancer.create();
    }
    @Override
    public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("我是媒婆,的给你找个异性才可以");
        System.out.println("开始海选");
        System.out.println("--------");
        //这个obj的引用是由CGLib给我们new出来的,CGLib new出来的对象,是被代理的对象的子类(继承了我们写的类)
        //OOP,在new子类之前,实际上默认先调用了我们的super()方法
        //new了子类的同时,必须先new出来父类,这就相当于是间接的持有了我们父类的引用
        //子类重写了父类的所有方法,我们改变了子类对象的某些属性,是可以间接的操作父类的属性
        Object result = methodProxy.invokeSuper(object, args);
        System.out.println("--------");
        System.out.println("如果合适的话,就准备办事");
        return result;
    }
}

最后创建测试类CGLibProxyTest.java

package com.packer.partten.factory.proxy.cglib;

/**
 * Created by lijianfang on 2021/9/27.
 */
public class CGLibProxyTest {
    public static void main(String[] args) {
        //JDK的动态代理是通过接口来进行强制转换的
        //生成以后的的代理对象,可以强制转换成接口

        //CGLib的动态代理是通过生成一个被代理对象的子类,然后重写父类的方法
        //生成以后的对象,可以强制转换为被代理对象(自己写的类)
        //子类引用赋值给父类
        try{
            xiaoming obj = (xiaoming) new Meipo().getInstance(xiaoming.class);
            obj.findLove();
        }catch (Exception e){
            System.out.println("报错了"+e);
        }
    }
}

测试结果:

我是媒婆,的给你找个异性才可以
开始海选
--------
找对象的要求:肤白貌美大长腿
--------
如果合适的话,就准备办事

Process finished with exit code 0

动态代理方式二:JDK动态代理,JDK的动态代理是通过接口来进行强制转换的,生成以后的的代理对象,可以强制转换成接口。

原理:

1.拿到被代理对象的引用,然后获取它的接口

2.JDK代理重新生成一个类,同时实现我们给的代理对象所实现的接口

3.把被代理对象的引用也拿到了

4.重新动态生成一个class字节码

5.然后编译

我们举一个例子,代码如下:

新建一个person.java类

package com.packer.partten.factory.proxy.jdk;

/**
 * Created by lijianfang on 2021/10/2.
 */
public interface Person {
    //寻找真爱、相亲
    void findLove();
    //获取性别
	String getSex();
    //获取名字
	String getName();
}

新建一个小明xiaoming.java类,实现person的接口,代码如下:

package com.packer.partten.factory.proxy.jdk;
    
    /**
     * Created by lijianfang on 2021/10/2.
     */
    public class xiaoming implements Person {
        private String sex = "女";
        private String name = "小明";
        /**
         * 找对象
         */
        @Override
        public void findLove() {
            System.out.println("我叫" + this.name + ",性别:" + this.sex + "我找对象的要求是:");
            System.out.println("高富帅");
            System.out.println("有房有车的");
            System.out.println("身高要求180cm以上,体重70kg");
        }
    
        /**
         * 获取性别
         * @return
         */
        @Override
        public String getSex() {
            return null;
        }
    
        /**
         * 获取名字
         * @return
         */
        @Override
        public String getName() {
            return null;
        }
    
        public void setSex(String sex) {
            this.sex = sex;
        }
    
        public void setName(String name) {
            this.name = name;
        }
   
    }

在新建meipo.java类,代码如下:

package com.packer.partten.factory.proxy.jdk;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * Created by lijianfang on 2021/10/2.
 */
public class Meipo implements InvocationHandler {
    private Person target; //被代理对象的引用作为一个成员变量保存下来了

    //获取被代理人的个人资料
    public Object getInstance(Person target) throws Exception{
        this.target = target;
        Class clazz = target.getClass();
        System.out.println("被代理对象的class是:"+clazz);
        return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("我是媒婆:" + "得给你找个异性才行");
        System.out.println("开始进行海选...");
        System.out.println("------------");

        //调用的时候
        method.invoke(this.target, args);
        System.out.println("------------");
        System.out.println("如果合适的话,就准备办事");
        return null;
    }
}

最后新建测试类JdkProxyTest.java类,代码如下:

package com.packer.partten.factory.proxy.jdk;

/**
 * Created by lijianfang on 2021/10/2.
 */
public class JdkProxyTest {
    public static void main(String[] args) throws Exception {
        //原理:
        //1.拿到被代理对象的引用,然后获取它的接口
        //2.JDK代理重新生成一个类,同时实现我们给的代理对象所实现的接口
        //3.把被代理对象的引用也拿到了
        //4.重新动态生成一个class字节码
        //5.然后编译
        Person person = (Person) new Meipo().getInstance(new xiaoming());
        System.out.println(person.getClass());
        person.findLove();
    }
}

测试结果如下:

被代理对象的class是:class com.packer.partten.factory.proxy.jdk.xiaoming
class com.sun.proxy.$Proxy0
我是媒婆:得给你找个异性才行
开始进行海选...
------------
我叫小明,性别:女我找对象的要求是:
高富帅
有房有车的
身高要求180cm以上,体重70kg
------------
如果合适的话,就准备办事

Process finished with exit code 0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值