设计模式之代理模式

设计模式之代理模式

应用场景:为其他对象提供一种代理以控制对这个对象的访问。从结构上来看和 Decorator 模式类似,
但 Proxy 是控制,更像是一种对功能的限制,而 Decorator 是增加职责。
Spring 的 Proxy 模式在 AOP 中有体现,比如 JdkDynamicAopProxy 和 Cglib2AopProxy。

设计模式之代理模式_第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() {

    }
}

代理类

// 静态代理
public class Father {
    // 静态代理对象
    private Son son;
    //没办法扩展
    public Father(Son son){// 代理对象使用构造方法传入
        this.son=son;
    }
    //目标对象的引用给拿到
    public void findLove(){
        System.out.println("根据你的要求物色");
        this.son.findLove();
        System.out.println("双方父母是不是同意");
    }

}

测试

 @Test
    public void findLove() {
        //只能帮儿子找对象
        //不能帮表妹、不能帮陌生人
        Father father = new Father(new Son());

        father.findLove();

        /**
         *  输出:
         *  根据你的要求物色
         * 找对象,肤白貌美大长腿
         * 双方父母是不是同意
         */
    }

jdk动态代理

jdk 动态代理需要实现代理接口【Person】

//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("找工作");
    }
}

代理接口

/**
 * 动态代理,需要实现{@link InvocationHandler}
 * @since 动态代理
 */

public class JDKMeipo implements InvocationHandler {

    //被代理的对象,把引用给保存下来
    private Person target;

    public Object getInstance(Person target){
        this.target=target;
        Class<? extends Person> targetClass = target.getClass();
        //解字节码是如何重组的
        //用来生成一个新的对象(字节码重组来实现)
       return Proxy.newProxyInstance(targetClass.getClassLoader(),targetClass.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;
    }
}

测试

 @Test
    public void getInstance() {
        try {
            Person obj = (Person)new JDKMeipo().getInstance(new XieMu());
            System.out.println(obj.getClass());
            obj.findJob();
            //原理:
            //1、拿到被代理对象的引用,并且获取到它的所有的接口,反射获取
            //2、JDK Proxy类重新生成一个新的类、同时新的类要实现被代理类所有实现的所有的接口
            //3、动态生成Java代码,把新加的业务逻辑方法由一定的逻辑代码去调用(在代码中体现)
            //4、编译新生成的Java代码.class
            //5、再重新加载到JVM中运行
            //以上这个过程就叫字节码重组
            //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();
        }
    }

cglib代理

public class ZhangSan {

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

}

代理类

/**
 * 使用Cglib实现动态代理{@link MethodInterceptor}
 */
public class CglibMeipo implements MethodInterceptor {

    public Object getInstance(Class<?> clazz){
        Enhancer enhancer = new Enhancer();
      //要把哪个设置为即将生成的新类父类
        enhancer.setSuperclass(clazz);
        // 回调执行intercept方法对目标对象功能的增强
        enhancer.setCallback(this);
        Object o = enhancer.create();
        return o;
    }


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

测试

 @Test
    public void getInstance() {

            try {
                ZhangSan obj = (ZhangSan)new CglibMeipo().getInstance(ZhangSan.class);
                obj.findLove();
                System.out.println("--------------------------------");
                // System.out.println(obj.getClass());
                /**
                 * 输出:
                 * 我是媒婆:我要给你找对象,现在已经拿到你的需求
                 * 开始物色
                 * 肤白貌美大象腿
                 * 如果合适的话,就准备办事
                 * --------------------------------
                 */
            } catch (Exception e) {
                e.printStackTrace();
            }

    }

自定义动态代理

/**
 *  自定义动态代理
 */
public class GPProxy {
    public static final String ln = "\r\n";

    public static Object newProxyInstance(GPClassLoader classLoader,Class<?> [] interfaces,GPInvocationHandler h){

        try {
            //1、动态生成源代码.java文件

            String src = generateSrc(interfaces);

            //2、Java文件输出磁盘
            String filePath = GPProxy.class.getResource("").getPath();
            System.out.println(filePath);
            File f = new File(filePath + "$Proxy0.java");
            FileWriter fw = new FileWriter(f);
            fw.write(src);
            fw.flush();
            fw.close();

            //3、把生成的.java文件编译成.class文件
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager manage = compiler.getStandardFileManager(null,null,null);
            Iterable iterable = manage.getJavaFileObjects(f);

            JavaCompiler.CompilationTask task = compiler.getTask(null,manage,null,null,null,iterable);
            task.call();
            manage.close();

            //4、编译生成的.class文件加载到JVM中来
            Class proxyClass =  classLoader.findClass("$Proxy0");
            Constructor c = proxyClass.getConstructor(GPInvocationHandler.class);
            f.delete();

            //5、返回字节码重组以后的新的代理对象
            return c.newInstance(h);
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    private static String generateSrc(Class<?>[] interfaces){

        StringBuffer sb = new StringBuffer();
        sb.append("package com.gupaoedu.vip.pattern.proxy.custom;" + ln);
        sb.append("import com.gupaoedu.vip.pattern.proxy.staticed.Person;" + ln);
        sb.append("import java.lang.reflect.Method;" + ln);
        sb.append("public class $Proxy0 implements " + interfaces[0].getName() + "{" + ln);

        sb.append("GPInvocationHandler h;" + ln);

        sb.append("public $Proxy0(GPInvocationHandler h) { " + ln);

        sb.append("this.h = h;");

        sb.append("}" + ln);


        for (Method m : interfaces[0].getMethods()){
            sb.append("public " + m.getReturnType().getName() + " " + m.getName() + "() {" + ln);
            sb.append("try{" + ln);
            sb.append("Method m = " + interfaces[0].getName() + ".class.getMethod(\"" + m.getName() + "\",new Class[]{});" + ln);
            sb.append("this.h.invoke(this,m,null);" + ln);
            sb.append("}catch(Throwable e){" + ln);
            sb.append("e.printStackTrace();" + ln);
            sb.append("}");
            sb.append("}");
        }

        sb.append("}" + ln);

        return sb.toString();
    }



}

GPInvocationHandler

public interface GPInvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}

GPClassLoader

public class GPClassLoader extends ClassLoader{

    private File classPathFile;

    public GPClassLoader(){
        String classPath = GPClassLoader.class.getResource("").getPath();
        this.classPathFile = new File(classPath);
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {

        String className = GPClassLoader.class.getPackage().getName() + "." + name;

        if(classPathFile != null){
            File classFile = new File(classPathFile,name.replaceAll("\\.","/") + ".class");
            if(classFile.exists()){
                FileInputStream in = null;
                ByteArrayOutputStream out = null;

                try{
                    in = new FileInputStream(classFile);
                    out = new ByteArrayOutputStream();
                    byte [] buff = new byte[1024];
                    int len;
                    while ((len = in.read(buff)) != -1){
                        out.write(buff,0,len);
                    }
                    return  defineClass(className,out.toByteArray(),0,out.size());
                }catch (Exception e){
                    e.printStackTrace();
                }finally {
                    if(null != in){
                        try {
                            in.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }

                    if(out != null){
                        try {
                            out.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }

        }

        return null;

    }
}

CustomMeipo

public class CustomMeipo implements  GPInvocationHandler {

    //被代理的对象,把引用给保存下来
    private Person target;

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

        Class<?> clazz = target.getClass();

        //下半截,老师深入底层来给大家讲解字节码是如何重组的
        //用来生成一个新的对象(字节码重组来实现)
        return GPProxy.newProxyInstance(new GPClassLoader(),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 static void main(String[] args) {

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

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

你可能感兴趣的:(设计模式,spring源码解析)