Java デザインモードでプロキシモードを記述する複数の方法 (3)

バックグラウンド

プロキシモードは構造モードに属しており、開発においてよく使われるデザインモードの一つでもありますが、今回はプロキシモードをより早く理解していただくために、以下のプロキシモードの書き方について説明していきます。これには、動的プロキシを自分で記述する方法も含まれます。

静的プロキシ

package com.example.proxy.staticProxy;

public interface IPerson {
    
    
    String findJob();
}
package com.example.proxy.staticProxy;

public class Customer implements  IPerson{
    
    
    @Override
    public String findJob() {
    
    
        return "工作要求:高薪,双休,福利好,事少,压力小";
    }
}

package com.example.proxy.staticProxy;

public class CustomFather implements IPerson{
    
    
    private IPerson iPerson;

    //客户老爸知道他儿子的要求
    public CustomFather(IPerson iPerson) {
    
    
        this.iPerson = iPerson;
    }

    public static void main(String[] args) {
    
    
        CustomFather bossProxy=new CustomFather(new Customer());
        bossProxy.findJob();
    }

    @Override
    public String findJob() {
    
    
        before();
        System.out.println(iPerson.findJob());
        after();
        return null;
    }

    private void after() {
    
    
        System.out.println("找到了,结束....");

    }

    private void before() {
    
    
        System.out.println("客户老爸开始给儿子物色工作....");
    }
}

package com.example.proxy.staticProxy;

public class StaticProxyTest {
    
    
    public static void main(String[] args) {
    
    
        //静态代理也可以使用,只是代理的对象个数很少,如果有其他人也要找工作并不适配,且客户老爸这个类也要经常进行修改
        CustomFather customFather = new CustomFather(new Customer());
        customFather.findJob();
    }
}

ここに画像の説明を挿入

JDK動的プロキシ

package com.example.proxy.jdkProxy;

public interface IPerson {
    
    
    String findJob();
}

package com.example.proxy.jdkProxy;



public class Customer implements IPerson {
    
    
    @Override
    public String findJob() {
    
    
        return "工作要求:高薪,双休,福利好,事少,压力小";
    }
}

package com.example.proxy.jdkProxy;


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

public class JdkProxy implements InvocationHandler {
    
    

    private IPerson iPerson;

    public IPerson getProxy(IPerson iPerson) {
    
    
        this.iPerson = iPerson;
        Class clz = iPerson.getClass();
        return (IPerson) Proxy.newProxyInstance(clz.getClassLoader(), clz.getInterfaces(), this);
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
        before();
        System.out.println(method.invoke(this.iPerson, args));
        after();
        return null;
    }

    private void after() {
    
    
        System.out.println("找到了,结束....");
    }

    private void before() {
    
    
        System.out.println("客户老爸开始给儿子物色工作....");
    }
}

package com.example.proxy.jdkProxy;


public class JdkProxyTest {
    
    
    public static void main(String[] args) {
    
    
        //动态代理,增加客户需求接口,代理类不需要经常变化,单要比cglib的动态代理性能要差一点
        JdkProxy jdkProxy = new JdkProxy();
        IPerson iPerson = jdkProxy.getProxy(new Customer());
        iPerson.findJob();
        
		//使用jdk的工具生成代理类的字节码文件,然后我们可以安装jad反编译工具,进行反编译
        byte bytes[]=ProxyGenerator.generateProxyClass("$Proxy0",new Class[]{
    
    IPerson.class});
        try {
    
    
            FileOutputStream fileOutputStream=new FileOutputStream(new File("d://$Proxy.class"));
            fileOutputStream.write(bytes);
            fileOutputStream.close();
        } catch (FileNotFoundException e) {
    
    
            throw new RuntimeException(e);
        } catch (IOException e) {
    
    
            throw new RuntimeException(e);
        }
    }
}

ここに画像の説明を挿入
ここに画像の説明を挿入

Jadダウンロードファイルアドレス:https://varaneckas.com/jad/

ここに画像の説明を挿入

cglib動的プロキシ

package com.example.proxy.cglibProxy;

public class Customer   {
    
    

    public String findJob() {
    
    
        return "工作要求:高薪,双休,福利好,事少,压力小";
    }
}

package com.example.proxy.cglibProxy;

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

import java.lang.reflect.Method;

public class CglibProxy implements MethodInterceptor {
    
    

    public Object getProxy(Class<?> clz) {
    
    
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clz);
        enhancer.setCallback(this);
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    
    
        before();
        System.out.println(methodProxy.invokeSuper(o,objects));
        after();
        return null;
    }

    private void after() {
    
    
        System.out.println("找到了,结束....");
    }

    private void before() {
    
    
        System.out.println("客户老爸开始给儿子物色工作....");
    }
}

package com.example.proxy.cglibProxy;

public class CglibProxyTest {
    
    
    public static void main(String[] args) {
    
    
        // cglib的动态代理推荐使用,因为性能比jdk都好
        // 注意custom类中不能用final修饰的方法
        CglibProxy cglibProxy = new CglibProxy();
        Customer customer = (Customer) cglibProxy.getProxy(new Customer().getClass());
        customer.findJob();
    }
}

ここに画像の説明を挿入

jdk動的プロキシを模倣して動的プロキシを自ら実現する

基礎となる実装に慣れるのが簡単

package com.example.proxy.customProxy;

public interface IMyPerson {
    
    
    String findJob();
}

package com.example.proxy.customProxy;

import java.io.*;

public class MyClassLoader extends ClassLoader {
    
    
    private File classFilePath;

    public MyClassLoader() {
    
    
        this.classFilePath = new File(MyClassLoader.class.getResource("").getPath());
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
    
    
        String classname = MyClassLoader.class.getPackage().getName() + "." + name;
        if (classFilePath != null) {
    
    
            File file = new File(classFilePath, name.replaceAll("\\.","/") + ".class");
            if (file.exists()) {
    
    
                try {
    
    
                    FileInputStream fis = new FileInputStream(file);
                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
                    byte buff[] = new byte[1024];
                    int len;
                    while ((len = fis.read(buff)) != -1) {
    
    
                        bos.write(buff, 0, len);
                    }
                    return defineClass(classname, bos.toByteArray(), 0, bos.size());
                } catch (Exception e) {
    
    
                    throw new RuntimeException(e);
                }
            }
        }
        return null;
    }
}

package com.example.proxy.customProxy;


import com.example.proxy.jdkProxy.IPerson;

public class MyCustomer implements IMyPerson {
    
    
    @Override
    public String findJob() {
    
    
        return "工作要求:高薪,双休,福利好,事少,压力小";
    }
}

package com.example.proxy.customProxy;

import java.lang.reflect.Method;

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

package com.example.proxy.customProxy;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public class MyProxy {
    
    

    public static Object newProxyInstance(MyClassLoader loader,
                                          Class<?>[] interfaces,
                                          MyInvocationHandler h)
            throws IllegalArgumentException {
    
    
        //Step1 生成代理类的java文件
        String originCode = generate(interfaces);
        //System.out.println(originCode);
        //Step2 把生成代理类的java文件写到磁盘$Proxy0.java
        String path = MyProxy.class.getResource("").getPath();
        File file = new File(path + "$Proxy0.java");
        try {
    
    
            FileWriter fileWriter = new FileWriter(file);
            fileWriter.write(originCode);
            fileWriter.flush();
            fileWriter.close();

            //Step3 将java文件编译成class文件$Proxy0.class
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null);
            Iterable iterable = manager.getJavaFileObjects(file);

            JavaCompiler.CompilationTask compilationTask = compiler.getTask(null, manager, null, null, null, iterable);
            compilationTask.call();
            manager.close();


            //Step4 将class文件加载到jvm中
            Class clz = loader.findClass("$Proxy0");
            Constructor constructor = clz.getConstructor(MyInvocationHandler.class);


            //Step5 将生成java文件删除
            file.delete();

            return constructor.newInstance(h);

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

    private static String generate(Class<?>[] interfaces) {
    
    
        String ln = "\r\n";
        StringBuffer sb = new StringBuffer();
        sb.append("package com.example.proxy.customProxy;" + ln);
        sb.append("import java.lang.reflect.*;" + ln);
        sb.append("import com.example.proxy.customProxy.IMyPerson;" + ln);

        sb.append("public class $Proxy0 implements " + interfaces[0].getName() + " {" + ln);
        sb.append("private MyInvocationHandler h;" + ln);

        sb.append("    public $Proxy0(MyInvocationHandler invocationhandler)\n" +
                "    {
    
    \n" + ln +
                "        this.h=invocationhandler;\n" + ln +
                "    }" + ln);
//方法由于我们只有一个,就写死了是一个,如果多个,可以用循环
        sb.append("public final String findJob()\n" + ln +
                "    {
    
    \n" + ln +
                "        try\n" + ln +
                "        {
    
    \n" + ln +
                "           Method m = com.example.proxy.customProxy.IMyPerson.class.getMethod(\"findJob\",new Class[]{});"+ ln +
                "            return (String)this.h.invoke(this, m, new Object[]{});\n" + ln +
                "        }\n" + ln +
                "        catch(Error _ex) { " + ln +
                "throw new UndeclaredThrowableException(_ex);" + ln +
                "}\n" + ln +
                "        catch(Throwable throwable)\n" + ln +
                "        {
    
    \n" +
                "            throw new UndeclaredThrowableException(throwable);\n" + ln +
                "        }\n" + ln +
                "    }" + ln);







        sb.append("}" + ln);


        return sb.toString();
    }

    private static String toLowerFirstCase(String src){
    
    
        char [] chars = src.toCharArray();
        chars[0] += 32;
        return String.valueOf(chars);
    }
    private static Map<Class,Class> mappings = new HashMap<Class, Class>();
    static {
    
    
        mappings.put(int.class,Integer.class);
    }

    private static String getReturnEmptyCode(Class<?> returnClass){
    
    
        if(mappings.containsKey(returnClass)){
    
    
            return "return 0;";
        }else if(returnClass == void.class){
    
    
            return "";
        }else {
    
    
            return "return null;";
        }
    }

    private static String getCaseCode(String code,Class<?> returnClass){
    
    
        if(mappings.containsKey(returnClass)){
    
    
            return "((" + mappings.get(returnClass).getName() +  ")" + code + ")." + returnClass.getSimpleName() + "Value()";
        }
        return code;
    }

    private static boolean hasReturnValue(Class<?> clazz){
    
    
        return clazz != void.class;
    }

}

package com.example.proxy.customProxy;

import java.lang.reflect.Method;

public class MyProxyProxy implements MyInvocationHandler{
    
    

    private IMyPerson iMyPerson;

    public IMyPerson getProxy(IMyPerson iMyPerson) {
    
    
        this.iMyPerson = iMyPerson;
        Class<?> clz=iMyPerson.getClass();
        return (IMyPerson) MyProxy.newProxyInstance(new MyClassLoader(),clz.getInterfaces(),this);
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
        before();
        System.out.println(method.invoke(this.iMyPerson, args));
        after();
        return null;
    }

    private void after() {
    
    
        System.out.println("找到了,结束....");
    }

    private void before() {
    
    
        System.out.println("客户老爸开始给儿子物色工作....");
    }

}

package com.example.proxy.customProxy;



public class MyProxyProxyTest {
    
    


    public static void main(String[] args) {
    
    
        //动态代理,增加客户需求接口,代理类不需要经常变化,单要比cglib的动态代理性能要差一点
        MyProxyProxy myProxyProxy = new MyProxyProxy();
        IMyPerson iPerson = myProxyProxy.getProxy(new MyCustomer());
        iPerson.findJob();
    }
}

ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/qq_40351360/article/details/128432085
おすすめ