欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

PowerJob的OhMyClassLoader工作流程源碼解讀

 更新時間:2024年01月18日 10:30:58   作者:codecraft  
這篇文章主要介紹了PowerJob的OhMyClassLoader工作流程源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

本文主要研究一下PowerJob的OhMyClassLoader

OhMyClassLoader

tech/powerjob/worker/container/OhMyClassLoader.java

@Slf4j
public class OhMyClassLoader extends URLClassLoader {

    public OhMyClassLoader(URL[] urls, ClassLoader parent) {
        super(urls, parent);
    }

    /**
     * 主動加載類,否則類加載器內(nèi)空空如也,Spring IOC容器初始化不到任何東西
     * @param packageName 包路徑,主動加載用戶寫的類
     * @throws Exception 加載異常
     */
    public void load(String packageName) throws Exception {
        URL[] urLs = getURLs();
        for (URL jarURL : urLs) {
            JarFile jarFile = new JarFile(new File(jarURL.toURI()));
            Enumeration<JarEntry> entries = jarFile.entries();
            while (entries.hasMoreElements()) {
                JarEntry jarEntry = entries.nextElement();
                if (jarEntry.isDirectory()) {
                    continue;
                }
                String name = jarEntry.getName();
                if (!name.endsWith(".class")) {
                    continue;
                }

                // 轉(zhuǎn)換 org/spring/AAA.class -> org.spring.AAA
                String tmp = name.substring(0, name.length() - 6);
                String res = StringUtils.replace(tmp, "/", ".");

                if (res.startsWith(packageName)) {
                    loadClass(res);
                    log.info("[OhMyClassLoader] load class({}) successfully.", res);
                }
            }
        }
    }
}
OhMyClassLoader繼承了URLClassLoader,它定義了load方法,遍歷urls,挨個根據(jù)url創(chuàng)建JarFile,然后遍歷jarFile.entries(),找到.class結(jié)尾的entry,判斷是否是packageName開頭的,是則執(zhí)行父類的loadClass方法

OmsJarContainer

tech/powerjob/worker/container/OmsJarContainer.java

@Slf4j
public class OmsJarContainer implements OmsContainer {

    private final Long containerId;
    private final String name;
    private final String version;
    private final File localJarFile;
    private final Long deployedTime;

    // 引用計數(shù)器
    private final AtomicInteger referenceCount = new AtomicInteger(0);

    private OhMyClassLoader containerClassLoader;
    private ClassPathXmlApplicationContext container;

    private final Map<String, BasicProcessor> processorCache = Maps.newConcurrentMap();

    public OmsJarContainer(Long containerId, String name, String version, File localJarFile) {
        this.containerId = containerId;
        this.name = name;
        this.version = version;
        this.localJarFile = localJarFile;
        this.deployedTime = System.currentTimeMillis();
    }

    @Override
    public void init() throws Exception {

        log.info("[OmsJarContainer-{}] start to init container(name={},jarPath={})", containerId, name, localJarFile.getPath());

        URL jarURL = localJarFile.toURI().toURL();

        // 創(chuàng)建類加載器(父類加載為 Worker 的類加載)
        this.containerClassLoader = new OhMyClassLoader(new URL[]{jarURL}, this.getClass().getClassLoader());

        // 解析 Properties
        Properties properties = new Properties();
        try (InputStream propertiesURLStream = containerClassLoader.getResourceAsStream(ContainerConstant.CONTAINER_PROPERTIES_FILE_NAME)) {

            if (propertiesURLStream == null) {
                log.error("[OmsJarContainer-{}] can't find {} in jar {}.", containerId, ContainerConstant.CONTAINER_PROPERTIES_FILE_NAME, localJarFile.getPath());
                throw new PowerJobException("invalid jar file because of no " + ContainerConstant.CONTAINER_PROPERTIES_FILE_NAME);
            }

            properties.load(propertiesURLStream);
            log.info("[OmsJarContainer-{}] load container properties successfully: {}", containerId, properties);
        }
        String packageName = properties.getProperty(ContainerConstant.CONTAINER_PACKAGE_NAME_KEY);
        if (StringUtils.isEmpty(packageName)) {
            log.error("[OmsJarContainer-{}] get package name failed, developer should't modify the properties file!", containerId);
            throw new PowerJobException("invalid jar file");
        }

        // 加載用戶類
        containerClassLoader.load(packageName);

        // 創(chuàng)建 Spring IOC 容器(Spring配置文件需要填相對路徑)
        // 需要切換線程上下文類加載器以加載 JDBC 類驅(qū)動(SPI)
        ClassLoader oldCL = Thread.currentThread().getContextClassLoader();
        Thread.currentThread().setContextClassLoader(containerClassLoader);
        try {
            this.container = new ClassPathXmlApplicationContext(new String[]{ContainerConstant.SPRING_CONTEXT_FILE_NAME}, false);
            this.container.setClassLoader(containerClassLoader);
            this.container.refresh();
        }finally {
            Thread.currentThread().setContextClassLoader(oldCL);
        }

        log.info("[OmsJarContainer-{}] init container(name={},jarPath={}) successfully", containerId, name, localJarFile.getPath());
    }

    //......
}
OmsJarContainer的init方法會使用構(gòu)造器傳入的localJarFile作為url創(chuàng)建OhMyClassLoader,然后讀取oms-worker-container.properties,以其中的PACKAGE_NAME屬性作為packageName,然后使用containerClassLoader.load進行加載

deployContainer

tech/powerjob/worker/container/OmsContainerFactory.java

public static synchronized void deployContainer(ServerDeployContainerRequest request) {

        Long containerId = request.getContainerId();
        String containerName = request.getContainerName();
        String version = request.getVersion();

        log.info("[OmsContainer-{}] start to deploy container(name={},version={},downloadUrl={})", containerId, containerName, version, request.getDownloadURL());

        OmsContainer oldContainer = CARGO.get(containerId);
        if (oldContainer != null && version.equals(oldContainer.getVersion())) {
            log.info("[OmsContainer-{}] version={} already deployed, so skip this deploy task.", containerId, version);
            return;
        }

        String filePath = CONTAINER_DIR + containerId + "/" + version + ".jar";
        // 下載Container到本地
        File jarFile = new File(filePath);

        try {
            if (!jarFile.exists()) {
                FileUtils.forceMkdirParent(jarFile);
                FileUtils.copyURLToFile(new URL(request.getDownloadURL()), jarFile, 5000, 300000);
                log.info("[OmsContainer-{}] download jar successfully, path={}", containerId, jarFile.getPath());
            }

            // 創(chuàng)建新容器
            OmsContainer newContainer = new OmsJarContainer(containerId, containerName, version, jarFile);
            newContainer.init();

            // 替換容器
            CARGO.put(containerId, newContainer);
            log.info("[OmsContainer-{}] deployed new version:{} successfully!", containerId, version);

            if (oldContainer != null) {
                // 銷毀舊容器
                oldContainer.destroy();
            }

        } catch (Exception e) {
            log.error("[OmsContainer-{}] deployContainer(name={},version={}) failed.", containerId, containerName, version, e);
            // 如果部署失敗,則刪除該 jar(本次失敗可能是下載jar出錯導(dǎo)致,不刪除會導(dǎo)致這個版本永久無法重新部署)
            CommonUtils.executeIgnoreException(() -> FileUtils.forceDelete(jarFile));
        }
    }
OmsContainerFactory提供了deployContainer方法,它會根據(jù)containerId以及version去下載指定的jar包,然后創(chuàng)建OmsJarContainer,執(zhí)行init方法

小結(jié)

OhMyClassLoader繼承了URLClassLoader,它定義了load方法,遍歷urls,挨個根據(jù)url創(chuàng)建JarFile,然后遍歷jarFile.entries(),找到.class結(jié)尾的entry,判斷是否是packageName開頭的,是則執(zhí)行父類的loadClass方法。不過這里貌似沒有對JarFile進行關(guān)閉,可能會導(dǎo)致資源泄露。

以上就是PowerJob的OhMyClassLoader工作流程源碼解讀的詳細(xì)內(nèi)容,更多關(guān)于PowerJob OhMyClassLoader的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論