实现生成工厂代码,实现热加载

简介: 实现生成工厂代码,实现热加载

背景:

设计模式开始学习工厂部分,分别为简单工厂,工厂方法,抽象工厂,目前的进度是学习到工厂方法,但是工厂方法需要手写加减乘除四个工厂,因为代码的重复性比较高,这些代码是不是能让机器来写呢?机器写好以后能不能直接让程序不停,根据传参可以生成类,并且执行方法呢?这一切都要依赖反射。

首先是实现自动生成工厂代码

思路:

1、写模板类(四个工厂,还有四个工厂客户端)

2、生成新类的时候替换其中的关键字即可。

下面是主函数中的东西:

Scanner scanner = new Scanner(System.in);
        System.out.println("请输入要创建的算法的模式:");
        className = scanner.nextLine();
        String srcFactoryCode = "package MoreAutoFactory;\n" +
                "public class" + " " + className + "Factory" + " " + "implements IFactory {\n" +
                "    @Override\n" +
                "    public Operation createOperation() {\n" +
                "        return new" + " " + "Operation"+className + "();\n" +
                "    }\n" +
                "}";
        //要创建文件的路径
        String path = "E:\\zy\\TGB-zgy-2022\\米老师设计模式课相关资料必须留着\\米老师设计模式课小例子\\JAVAtest\\Factory\\src\\main\\java\\MoreAutoFactory\\" + className + "Factory.java";
        File file = new File(path);
        if (!file.exists()) {
            if (file.createNewFile()) {
                System.out.println("新类型工厂文件创建成功");
                FileWriter fileWriter = new FileWriter(path);
                BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
                bufferedWriter.write(srcFactoryCode);
                bufferedWriter.close();
                //编译文件
                Compiler(System.getProperty("user.dir")+"\\Factory\\target\\classes",path);
            }
        }
        String srcClientCode = "package MoreAutoFactory;\n" +
                "public class" + " " + className + "Client" + " {\n" +
                "  public  void getEndResult() throws Exception {\n" +
                "      IFactory operFactory = new " + className + "Factory();\n" +
                "      Operation oper = operFactory.createOperation();\n" +
                "       oper.setNumberA(2);\n" +
                "       oper.setNumberB(2);\n" +
                "       double result = oper.getResult();\n " +
                "       System.out.println(result);\n" +
                "    }\n" +
                "}";
        //要创建文件的路径
        String pathClient = "E:\\zy\\TGB-zgy-2022\\米老师设计模式课相关资料必须留着\\米老师设计模式课小例子\\JAVAtest\\Factory\\src\\main\\java\\MoreAutoFactory\\" + className + "Client.java";
        File fileClient = new File(pathClient);
        if (!fileClient.exists()) {
            if (fileClient.createNewFile()) {
                System.out.println("新类型客户端文件创建成功");
                FileWriter fileWriter = new FileWriter(pathClient);
                BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
                bufferedWriter.write(srcClientCode);
                bufferedWriter.close();
                //编译文件
                Compiler(System.getProperty("user.dir")+"\\Factory\\target\\classes",pathClient);
            }
        }
    }

实现热加载

下面自定义类加载器

public class MyClasslLoader extends ClassLoader {
    /** 要加载的 Java 类的 classpath 路径 */
    private String classpath;
    public MyClasslLoader(String classpath) {
        // 指定父加载器
        super(ClassLoader.getSystemClassLoader());
        this.classpath = classpath;
    }
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] data = this.loadClassData(name);
        return this.defineClass(name, data, 0, data.length);
    }
    /**
     * 加载 class 文件中的内容
     *
     * @param name
     * @return
     */
    private byte[] loadClassData(String name) {
        try {
            // 传进来是带包名的
            name = name.replace(".", "//");
            FileInputStream inputStream = new FileInputStream(new File(classpath + name + ".class"));
            // 定义字节数组输出流
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            int b = 0;
            while ((b = inputStream.read()) != -1) {
                baos.write(b);
            }
            inputStream.close();
            return baos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

定义要实现热加载的类的接口

public interface BaseManager {
    public void logic() throws IOException, ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException;
}

定义实现类

public class MyManager implements BaseManager  {
    @Override
    public void logic() throws IOException, ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {
        create();
        reflect();
    }
//        System.out.println(LocalTime.now() + ": Java类的热加载");
        static String className = "";
        static String operationName = "";
    public static void create() throws IOException {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入要创建的算法的模式:");
        className = scanner.nextLine();
        String srcFactoryCode = "package MoreAutoFactory;\n" +
                "public class" + " " + className + "Factory" + " " + "implements IFactory {\n" +
                "    @Override\n" +
                "    public Operation createOperation() {\n" +
                "        return new" + " " + "Operation"+className + "();\n" +
                "    }\n" +
                "}";
        //要创建文件的路径
        String path = "E:\\zy\\TGB-zgy-2022\\米老师设计模式课相关资料必须留着\\米老师设计模式课小例子\\JAVAtest\\Factory\\src\\main\\java\\MoreAutoFactory\\" + className + "Factory.java";
        File file = new File(path);
        if (!file.exists()) {
            if (file.createNewFile()) {
                System.out.println("新类型工厂文件创建成功");
                FileWriter fileWriter = new FileWriter(path);
                BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
                bufferedWriter.write(srcFactoryCode);
                bufferedWriter.close();
                //编译文件
                Compiler(System.getProperty("user.dir")+"\\Factory\\target\\classes",path);
            }
        }
        String srcClientCode = "package MoreAutoFactory;\n" +
                "public class" + " " + className + "Client" + " {\n" +
                "  public  void getEndResult() throws Exception {\n" +
                "      IFactory operFactory = new " + className + "Factory();\n" +
                "      Operation oper = operFactory.createOperation();\n" +
                "       oper.setNumberA(2);\n" +
                "       oper.setNumberB(2);\n" +
                "       double result = oper.getResult();\n " +
                "       System.out.println(result);\n" +
                "    }\n" +
                "}";
        //要创建文件的路径
        String pathClient = "E:\\zy\\TGB-zgy-2022\\米老师设计模式课相关资料必须留着\\米老师设计模式课小例子\\JAVAtest\\Factory\\src\\main\\java\\MoreAutoFactory\\" + className + "Client.java";
        File fileClient = new File(pathClient);
        if (!fileClient.exists()) {
            if (fileClient.createNewFile()) {
                System.out.println("新类型客户端文件创建成功");
                FileWriter fileWriter = new FileWriter(pathClient);
                BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
                bufferedWriter.write(srcClientCode);
                bufferedWriter.close();
                //编译文件
                Compiler(System.getProperty("user.dir")+"\\Factory\\target\\classes",pathClient);
            }
        }
    }
        public static void reflect() throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
            String str = "MoreAutoFactory."+className+"Client";
            System.out.println(str);
            Class classClient = Class.forName("MoreAutoFactory."+className+"Client");
            Object object = classClient.newInstance();
            Method getEndResultMethod = classClient.getMethod("getEndResult");
            getEndResultMethod.invoke(object,null);
        }
        public static void Compiler(String compilerPath,String javaPath){
            JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
//            int status = javac.run(null, null, null, "-d", System.getProperty("user.dir")+"\\target\\classes\\MoreAutoFactory","D:/test/AlTest.java");
            int status = javac.run(null, null, null, "-d", compilerPath,javaPath);
            if(status!=0){
                System.out.println("没有编译成功!");
            }
        }
}
public class MyClasslLoader extends ClassLoader {
    /** 要加载的 Java 类的 classpath 路径 */
    private String classpath;
    public MyClasslLoader(String classpath) {
        // 指定父加载器
        super(ClassLoader.getSystemClassLoader());
        this.classpath = classpath;
    }
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] data = this.loadClassData(name);
        return this.defineClass(name, data, 0, data.length);
    }
    /**
     * 加载 class 文件中的内容
     *
     * @param name
     * @return
     */
    private byte[] loadClassData(String name) {
        try {
            // 传进来是带包名的
            name = name.replace(".", "//");
            FileInputStream inputStream = new FileInputStream(new File(classpath + name + ".class"));
            // 定义字节数组输出流
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            int b = 0;
            while ((b = inputStream.read()) != -1) {
                baos.write(b);
            }
            inputStream.close();
            return baos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
public class MsgHandle implements Runnable {
    @Override
    public void run() {
        while (true) {
            BaseManager manager = ManagerFactory.getManager(ManagerFactory.MY_MANAGER);
            try {
                manager.logic();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
public class ManagerFactory {
    /** 记录热加载类的加载信息 */
    private static final Map<String, LoadInfo> loadTimeMap = new HashMap<>();
    /** 要加载的类的 classpath */
    public static final String CLASS_PATH = "E:\\zy\\TGB-zgy-2022\\米老师设计模式课相关资料必须留着\\米老师设计模式课小例子\\JAVAtest\\Factory\\target\\classes";
    /** 实现热加载的类的全名称(包名+类名 ) */
    public static final String MY_MANAGER = "hotLoad.MyManager";
    public static BaseManager getManager(String className) {
        File loadFile = new File(CLASS_PATH + className.replaceAll("\\.", "/") + ".class");
        // 获取最后一次修改时间
        long lastModified = loadFile.lastModified();
        System.out.println("当前的类时间:" + System.currentTimeMillis());
        // loadTimeMap 不包含 ClassName 为 key 的信息,证明这个类没有被加载,要加载到 JVM
        if (loadTimeMap.get(className) == null) {
            load(className, lastModified);
        } // 加载类的时间戳变化了,我们同样要重新加载这个类到 JVM。
        else if (loadTimeMap.get(className).getLoadTime() != lastModified) {
            load(className, lastModified);
        }
        return loadTimeMap.get(className).getManager();
    }
    /**
     * 加载 class ,缓存到 loadTimeMap
     *
     * @param className
     * @param lastModified
     */
    private static void load(String className, long lastModified) {
        MyClasslLoader myClasslLoader = new MyClasslLoader(className);
        Class loadClass = null;
        // 加载
        try {
            loadClass = myClasslLoader.loadClass(className);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        BaseManager manager = newInstance(loadClass);
        LoadInfo loadInfo = new LoadInfo(myClasslLoader, lastModified);
        loadInfo.setManager(manager);
        loadTimeMap.put(className, loadInfo);
    }
    /**
     * 以反射的方式创建 BaseManager 的子类对象
     *
     * @param loadClass
     * @return
     */
    private static BaseManager newInstance(Class loadClass) {
        try {
            return (BaseManager)loadClass.getConstructor(new Class[] {}).newInstance(new Object[] {});
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return null;
    }
}
public class LoadInfo {
    /** 自定义的类加载器 */
    private MyClasslLoader myClasslLoader;
    /** 记录要加载的类的时间戳-->加载的时间 */
    private long loadTime;
    /** 需要被热加载的类 */
    private BaseManager manager;
    public LoadInfo(MyClasslLoader myClasslLoader, long loadTime) {
        this.myClasslLoader = myClasslLoader;
        this.loadTime = loadTime;
    }
    public MyClasslLoader getMyClasslLoader() {
        return myClasslLoader;
    }
    public void setMyClasslLoader(MyClasslLoader myClasslLoader) {
        this.myClasslLoader = myClasslLoader;
    }
    public long getLoadTime() {
        return loadTime;
    }
    public void setLoadTime(long loadTime) {
        this.loadTime = loadTime;
    }
    public BaseManager getManager() {
        return manager;
    }
    public void setManager(BaseManager manager) {
        this.manager = manager;
    }
}
public class ClassLoadTest {
    public static void main(String[] args) {
        new Thread(new MsgHandle()).start();
    }
}

预知后事如何,请听下回分解。


相关文章
|
存储 测试技术 数据库
仓储设计实现问题之聚合实体在DDD中定义如何解决
仓储设计实现问题之聚合实体在DDD中定义如何解决
129 0
|
存储 关系型数据库 MySQL
MySQL为何偏爱B+树而非跳表?
【8月更文挑战第9天】在数据库的世界里,索引是提升查询效率的关键。而在MySQL这样的关系型数据库管理系统中,B+树作为索引结构的首选,其背后的原因值得我们深入探讨。本文将从技术角度解析,为何MySQL选择B+树而非跳表作为其索引结构的核心。
560 6
|
6月前
|
弹性计算 资源调度 搜索推荐
阿里云ECS中长期成本节省计划解析:从原理到实战,助力企业降本提效
阿里云ECS节省计划的推出为企业用户提供了一种全新的成本优化方案。通过一次性购买的方式享受长期按量付费的折扣权益,客户不仅可以大幅降低ECS资源的使用成本还可以享受更高的灵活性和便捷性。本文将从多个维度深入剖析阿里云ECS节省计划,包括其核心优势、详尽的购买使用指引、与传统付费模式的全面对比,以及一客户成功案例,以供大家了解和参考。
|
11月前
|
存储 监控 数据可视化
双十一线上服务调用链路追踪SkyWalking实战分析
【11月更文挑战第27天】随着电商行业的飞速发展,双十一购物节已成为全球最大的购物狂欢节之一。在双十一期间,电商平台需要处理海量的用户请求和订单,这对系统的稳定性和性能提出了极高的要求。为了确保系统在高并发环境下的稳定运行,对线上服务的调用链路进行追踪和分析显得尤为重要。本文将通过实战案例,详细介绍如何在双十一期间使用SkyWalking对线上服务进行调用链路追踪,并结合Seata实现分布式事务管理,从而保障系统的稳定性和性能。
327 6
|
SQL 运维 关系型数据库
will be dropped if server is in r-o mode问题解决
【6月更文挑战第26天】will be dropped if server is in r-o mode问题解决
326 2
|
监控 安全 Linux
【权限维持】Linux&OpenSSH&PAM后门&SSH软链接&公私钥登录
【权限维持】Linux&OpenSSH&PAM后门&SSH软链接&公私钥登录
256 2
|
设计模式 开发者 Python
深入理解Python适配器模式及其应用示例
在软件开发中,适配器模式是一种常用的设计模式,它可以帮助我们解决不兼容的接口或类之间的问题。通过适配器模式,我们可以简化不兼容接口之间的调用,并提高代码的复用性和可维护性。这两个支付接口具有不同的接口定义和调用方式,为了屏蔽这种差异性并实现统一的支付接口,可以使用适配器模式来完成。通过适配器模式,我们成功地将支付宝和微信支付的接口适配到了统一的支付接口上,实现了支付系统的可扩展性和灵活性。适配器模式的核心思想是创建一个中间层,将不同的接口进行适配,使得接口之间可以无缝衔接并协同工作。
200 2
|
程序员 编译器 C++
C++中的函数重载(Function Overloading)
C++中的函数重载(Function Overloading)
291 2
|
机器学习/深度学习 自然语言处理 JavaScript
Copilot概述
Copilot概述
369 0
|
监控 Java Linux
Apache JMeter5.2基础入门实践详解
Apache JMeter5.2基础入门实践详解
281 0