設計模式五 代理模式

0、基本定義

爲其餘對象提供一種代理以控制對這個對象對訪問。java

靜態代理:代理前,全部對行爲都是已知對。 不能擴展spring

動態代理:代理前,全部的行爲都是未知的。app

》 jdk:必須實現 interface,從interface中,獲取method,進行字節碼重組,生成新類。jvm

》 cgli:對類進行代理,Enhance 須要設置 被代理的類做爲 superClass,生成被代理類的子類。ide

 

一、代碼實現(gupao學院的demo)

1.1 靜態代理

public class Father {

    private Son person;

    //強依賴,不能擴展
    public Father(Son person) {
        this.person = person;
    }

    public void findLove() {

        System.out.println("開始五色");
        this.person.findLove();
        System.out.println("結束");
    }
}

public class Son {

    public void findLove() {

        System.out.println("找對象,大長腿");
    }

}

public class StaticProxyTest {

    public static void main(String[] args) {

        Son son = new Son();

        Father father = new Father(son);

        father.findLove();
    }
}

 

1.2  動態代理

採用tom老師經典案例,meipothis

jdk代理spa

public interface Person {

    void findLove();
    void job();
}

public class XieMu implements Person{

    @Override
    public void findLove() {

        System.out.println("gaofus");
        System.out.println("身高175");
        System.out.println("人好");
    }

    @Override
    public void job() {
        System.out.println("salary 》 15k");
    }
}


public class JDKMeipo implements InvocationHandler{

    private XieMu target;

    public Object getInstance(XieMu target) {

        this.target = target;

        //生成新類
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                this);

    }

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

        System.out.println( "我是媒婆,已經拿到需求");
        System.out.println( "開始五色");
        method.invoke(this.target,args);
        return null;
    }
}

public class JDK58 implements InvocationHandler{

    private Person target;

    public Object getInstance(Person target) {

        this.target = target;

        //生成新類
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                this);

    }

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

        System.out.println( "我是58,開始找工做 ");
        method.invoke(this.target,args);
        return null;
    }
}

public class JDKProxyTest {


    public static void main(String[] args) throws IOException {

//        Person instance = (Person) new JDKMeipo().getInstance(new XieMu());
//        instance.findLove();

        Person proxy = (Person) new JDK58().getInstance(new XieMu());
        proxy.job();

        byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{Person.class});
        FileOutputStream fos = new FileOutputStream("$Proxy.class");

        fos.write(bytes);
        fos.close();

    }
}

cgli 代理代理

public class Zhangsan {

    public void findLove() {
        System.out.println("人美");
    }
}

public class CglibMeipo implements MethodInterceptor {

    public Object getInstance(Class clazz) {

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


public class CglibTest {

    public static void main(String[] args) {

        Zhangsan instance = (Zhangsan) new CglibMeipo().getInstance(new Zhangsan().getClass());

        instance.findLove();

        System.out.println(instance.getClass());
    }
}

 

1.3 自定義代理

GPClassLoader.java調試

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 fis = null;
                ByteArrayOutputStream out = null;
                try {
                    fis = new FileInputStream(classFile);
                    out = new ByteArrayOutputStream();
                    byte[] buff = new byte[1024];
                    int len;
                    while ((len = fis.read(buff)) != -1) {
                        out.write(buff, 0, len);
                    }
                    return defineClass(className, out.toByteArray(), 0, out.size());
                } catch (Exception e) {

                } finally {
                    if (fis != null) {
                        try {
                            fis.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if (out != null) {
                        try {
                            out.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        return super.findClass(name);
    }
}

 

GPProxy.javacode

public class GPProxy {

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

        // 一、動態生成源代碼
        String src = generateSrc(interfaces);
        //二、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();

        //三、生成的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();

        //四、編譯生成的.class文件加載到jvm中
        Class proxyClass =  classLoader.findClass("$Proxy0");
        Constructor c = proxyClass.getConstructor(GPInvocationHandler.class);
        f.delete();
        //五、返回字節碼重組後的新的代理對象
        return c.newInstance(handler);
    }

    public static final String ln = "\r\n";
    private static String generateSrc(Class<?>[] interfaces) {

        StringBuffer sb = new StringBuffer();
        sb.append("package com.zzf.design.proxy.custom;" + ln);
        sb.append("import com.zzf.design.proxy.jdk.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();
    }
}

 

InvocationHandler.java

public interface GPInvocationHandler {

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

 

藉此機會熟悉了下 ClassLoader ,一些IO流使用。受益不少。在此紀錄。

代理過程當中 主要就是 字節碼重組,生成了一個新類 $Proxy.java 。在平時的調試過程當中,是找不到該類的,運行時使用後,就立馬刪除了。


字節碼重組原理 //一、拿到被代理對象的引用,並獲取它的全部接口,反射獲取 //二、jdk proxy 類從新生成一個新的類,同時新的類要實現被代理類全部實現方法 //三、動態生成Java代碼,把新加的業務邏輯方法由必定的邏輯代碼去調用 //四、編譯新生成的java代碼 .class //五、在從新加載到 jvm中運行

 

2 使用場景

spring AOP 是使用代理很好的一種實現。

 

==========================================

想學着用語言來進行描述,但還達不到程度,這更像是一份代碼筆記。

=========================================

參考資料:

咕泡學院

相關文章
相關標籤/搜索