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

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

背景:

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

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

思路:

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

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


相关文章
|
XML 缓存 Java
SpringBean(配置、实例化、作用域、生命周期、装配方式)
SpringBean(配置、实例化、作用域、生命周期、装配方式)
184 0
SpringBean(配置、实例化、作用域、生命周期、装配方式)
|
Java
ServiceLoader服务提供者模式,实现动态插件加载,类责任链模式
<div style="margin:0px; padding:0px; border:0px; line-height:1.428571em; font-family:Helvetica,Arial,'Droid Sans',sans-serif; font-size:14.4444446563721px"> <del style="margin:0px; padding:0px; b
3312 0
|
XML 存储 Java
【Spring注解驱动开发】使用@PropertySource加载配置文件,我只看这一篇!!
很多小伙伴都在问:冰河,你的Spring专题更新完了吗?怎么感觉像是写了一半啊?我:没有更新完呀,整个专题预计会有70多篇。那怎么更新了一半就去写别的了呢?那是因为有很多其他的小伙伴在后台留言说:急需学习一些其他的技术,所以,临时调整的。放心,Spring专题会持续更新的!这不,今天,我们就继续更新Spring专题。不出意外的话,会一直持续更新完!!
359 0
|
5月前
|
缓存 安全 Java
Spring框架中Bean是如何加载的?从底层源码入手,详细解读Bean的创建流程
从底层源码入手,通过代码示例,追踪AnnotationConfigApplicationContext加载配置类、启动Spring容器的整个流程,并对IOC、BeanDefinition、PostProcesser等相关概念进行解释
437 24
|
Java Spring 容器
Spring解析,加载及实例化Bean的顺序(零配置)
在A之前实例化好。很多时候Spring智能地为我们做好了这些工作,但某些情况下可能不是,比如Springboot的@AutoConfigureAfter注解,
Spring解析,加载及实例化Bean的顺序(零配置)
|
前端开发 Java Spring
|
Java Spring 数据库
第3章—高级装配—运行时注入
运行时注入 当我们经常用如下的硬解码方式来配置文件: 但有时我们需要避免硬解码,需要想要这些值在运行时确定,Spring提供了两种在运行时求值的方式: 属性占位符 Spring表达式语言(SpEL) 1.
1107 0
|
XML Java 数据格式
第四章:Spring框架装配Bean的三种方式(基础)
本章我们一起来探讨SpringBean的装配,所谓 ”装配“ 就是值将Bean安装Bean容器中并进行依赖关系配置,稍微提一下IOC控制反转就是指的安装这一过程中,而DI依赖指的是配置这一过程。本章我们就Spring应用中如何进行装配Bean进行讲解;如自动化装配,Java配置装配,XML配置装配方.
7463 0
|
前端开发 Java 数据库连接
【SSM】Bean 作用域和生命周期(重点:Bean 的生命周期5大部分)
本文重点介绍Bean 的 6 种作用域singleton、prototype、request、session、application、websocket:HTTP和Bean 的生命周期5大部分。
186 0
|
测试技术
Moq测试基础说谈(四)——Mock类,创建对象,实用工厂
Mock Class 定义为:   public class Mock : Mock where T : class   这的构造方法: Mock() Mock(MockBehavior) Mock(array[]) Mock(MockBehavior, array[])   Mock的泛型实现类,它有很多方法和属性。
1137 0

热门文章

最新文章