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

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

背景:

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

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

思路:

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

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


相关文章
|
4月前
|
Java
SpringBoot内部配置加载顺序
SpringBoot内部配置加载顺序
36 0
|
4月前
|
Java Maven
@ConditionalOnMissingBean 如何实现覆盖第三方组件中的 Bean
@ConditionalOnMissingBean 如何实现覆盖第三方组件中的 Bean
22 0
|
4月前
|
Java Maven
@ConditionalOnMissingBean 如何实现覆盖第三方组件中的 Bean
@ConditionalOnMissingBean 如何实现覆盖第三方组件中的 Bean
18 0
|
8月前
|
Java API Apache
springboot 调用外部接口的21种方式
springboot 调用外部接口的21种方式
461 0
|
9月前
|
C++
C++插件管理类(下)——实际项目(阉割版)
C++插件管理类(下)——实际项目(阉割版)
61 0
|
10月前
|
Dubbo Java 应用服务中间件
SpringBoot 调用外部接口的三种方式
SpringBoot 调用外部接口的三种方式
423 1
|
10月前
|
设计模式 存储 Java
Java版事件与委托实现自动创建工厂并热加载
Java版事件与委托实现自动创建工厂并热加载
Java版事件与委托实现自动创建工厂并热加载
|
10月前
|
Java
springboot自定义外部扩展文件
在springboot启动的时候调用run方法,可以看到run方法里面的内容,其中有一个getRunListeners方法
|
Java
Springboot加载动态Bean的10种方式
Springboot加载动态Bean的10种方式
501 0
springboot测试中主程序中能加载bean测试中无法加载bean
如遇到springboot版本的问题导致bean类无法注入到项目中,可能是注解和springboot版本不匹配导致启动类启动时扫描不到相应的bean类
springboot测试中主程序中能加载bean测试中无法加载bean