慕課網_《Spring Boot熱部署》學習總結

時間:2017年12月01日星期五
說明:本文部份內容均來自慕課網。@慕課網:http://www.imooc.com
教學源碼:無
學習源碼:https://github.com/zccodere/s...html

第一章:課程介紹

1-1 課程介紹

熱部署的使用場景java

本地調式
線上發佈

熱部署的使用優勢git

不管本地仍是線上,都適用
無需重啓服務器:提升開發、調式效率、提高發布、運維效率、下降運維成本

前置知識github

掌握Java語言
有必定的Spring開發經驗
掌握構建Spring Boot項目的方法

課程提綱web

原理解析
案例分析
項目演示
測試驗證
發佈程序
課程總結

第二章:原理解析

2-1 部署加載

Java熱部署與熱加載聯繫spring

不重啓服務器編譯或部署項目
基於Java的類加載器實現

Java熱部署與熱加載的區別設計模式

部署方式
--熱部署在服務器運行時從新部署項目
--熱加載在運行時從新加載class
實現原理
--熱部署直接從新加載整個應用
--熱加載在運行時從新加載class
使用場景
--熱部署更多的是在生產環境使用
--熱加載則更多的是在開發環境使用

2-2 原理解析

Java類的加載過程tomcat

clipboard.png

類加載的五個階段服務器

clipboard.png

Java類加載器特色架構

1.由AppClassLoader(系統類加載器)開始加載指定的類
2.類加載器將加載任務交給其父類,若是其父類找不到,再由本身去加載
3.BootstrapLoader(啓動類加載器)是最頂級的類加載器

Java類的熱部署

類的熱加載
配置Tomcat

經過類的熱加載實現熱部署

clipboard.png

經過配置Tomcat實現熱部署

1.直接把項目web文件夾放在webapps裏
2.在tomcat/conf/server.xml中的<host></host>內部添加<context/>標籤
3.在%tomcat_home%/conf/Catalina/localhost中添加一個XML

第三章:案例分析

3-1 案例介紹

寫一個Java類熱加載的實際案例,要求以下

1.類層次結構清晰,修改某一個Java類文件不須要重啓服務或者從新編譯運行程序
2.可適當的運用一些設計模式使代碼結構更加清晰明瞭,好比工廠模式等

3-2 案例實現

建立名爲classloader的gradle工程build.gradle腳本以下

apply plugin: 'java'
apply plugin: 'eclipse'

group = 'com.myimooc'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8

repositories {
    maven{ url "http://maven.aliyun.com/nexus/content/groups/public/"}
    mavenCentral()
}

dependencies {

}

代碼編寫

1.編寫MyClassLoader類

package com.myimooc.classloader;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;

/**
 * @title 自定義Java類加載器
 * @describe 來實現Java類的熱加載
 * @author zc
 * @version 1.0 2017-12-01
 */
public class MyClassLoader extends ClassLoader{
    
    /** 要加載的Java類的classpath路徑 */
    private String classpath;
    
    public MyClassLoader(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);
    }
    
    /**
     * @title 加載class文件中的內容
     * @describe 加載class文件中的內容
     * @author zc
     * @version 1.0 2017-12-01
     */
    private byte[] loadClassData(String name) {
        try{
            name = name.replace(".", "//");
            FileInputStream is = new FileInputStream(new File(this.classpath + name +".class"));
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            int b = 0;
            while((b = is.read()) != -1){
                baos.write(b);
            }
            is.close();
            return baos.toByteArray();
        }catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

2.編寫BaseManager類

package com.myimooc.classloader;

/**
 * @title 標識接口
 * @describe 實現這個接口的子類須要動態更新
 * @author zc
 * @version 1.0 2017-12-01
 */
public interface BaseManager {
    
    public void logic();
    
}

3.編寫MyManager類

package com.myimooc.classloader;

/**
 * @title 接口實現類
 * @describe BaseManager的子類,此類須要實現Java類的熱加載功能
 * @author zc
 * @version 1.0 2017-12-01
 */
public class MyManager implements BaseManager {

    @Override
    public void logic() {
        System.out.println("學習如何實現Java類的熱加載案例");
    }
}

4.編寫LoadInfo類

package com.myimooc.classloader;

/**
 * @title 類加載信息
 * @describe 封裝加載類的信息
 * @author zc
 * @version 1.0 2017-12-01
 */
public class LoadInfo {
    
    /** 自定義的類加載器 */
    private MyClassLoader myLoader;
    /** 記錄要加載類的時間戳,加載的時間 */
    private long loadTime;
    
    private BaseManager manager;

    public LoadInfo(MyClassLoader myLoader, long loadTime) {
        super();
        this.myLoader = myLoader;
        this.loadTime = loadTime;
    }

    public MyClassLoader getMyLoader() {
        return myLoader;
    }

    public void setMyLoader(MyClassLoader myLoader) {
        this.myLoader = myLoader;
    }

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

5.編寫ManagerFactory類

package com.myimooc.classloader;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

/**
 * @title Manager工廠類
 * @describe 加載manager的工廠
 * @author zc
 * @version 1.0 2017-12-01
 */
public class ManagerFactory {
    
    /** 記錄熱加載類的加載信息 */
    private static final Map<String,LoadInfo> loadTimeMap = new HashMap<String,LoadInfo>();
    
    /** 要加載的類的classpath路徑 */
    public static final String CLASS_PATH = "D:/AllSpace/ByStudy/classloader/bin/";
    
    /** 實現熱加載的類的全名稱(包名+類名) */
    public static final String MY_MANAGER = "com.myimooc.classloader.MyManager";
    
    public static BaseManager getManager(String className){
        File loadFile = new File(CLASS_PATH + className.replaceAll("\\.", "/")+".class");
        long lastModified = loadFile.lastModified();

        if(loadTimeMap.get(className)== null){
            // loadTimeMap不包含className爲key的LoadInfo信息。
            // 證實這個類沒有被加載,那麼須要加載這個類到JVM中
            load(className,lastModified);
            
        }else if(loadTimeMap.get(className).getLoadTime()!=lastModified){
            // 加載類的時間戳變化了,一樣要從新加載
            load(className,lastModified);
        }
        
        return loadTimeMap.get(className).getManager();
    }

    private static void load(String className, long lastModified) {
        MyClassLoader myClassLoader = new MyClassLoader(CLASS_PATH);
        Class<?> loadClass = null;
        try {
            loadClass = myClassLoader.findClass(className);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        BaseManager manager = newInstance(loadClass);
        LoadInfo loadInfo = new LoadInfo(myClassLoader,lastModified);
        loadInfo.setManager(manager);
        loadTimeMap.put(className, loadInfo);
    }

    /**
     * @title 建立實例對象
     * @describe 以反射的方式建立BaseManager子類對象
     * @author zc
     * @version 1.0 2017-12-01
     */
    private static BaseManager newInstance(Class<?> loadClass) {
        try {
            return (BaseManager)loadClass.getConstructor(new Class[]{}).newInstance(new Object[]{});
        } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
                | NoSuchMethodException | SecurityException e) {
            e.printStackTrace();
        }
        return null;
    }
}

6.編寫MsgHandler類

package com.myimooc.classloader;

/**
 * @title 後臺線程
 * @describe 後臺啓動一條線程不斷刷新加載實現了熱加載的類
 * @author zc
 * @version 1.0 2017-12-01
 */
public class MsgHandler implements Runnable{

    @Override
    public void run() {
        while(true){
            BaseManager manager = ManagerFactory.getManager(ManagerFactory.MY_MANAGER);
            manager.logic();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

7.編寫ClassLoaderTest類

package com.myimooc.classloader;

/**
 * @title 測試類
 * @describe 測試Java類的熱加載
 * @author zc
 * @version 1.0 2017-12-01
 */
public class ClassLoaderTest {
    
    public static void main(String[] args) {
        new Thread(new MsgHandler()).start();
    }
}

第四章:項目演示

4-1 簡單介紹

Spring Boot簡單介紹

是一個全新框架,目的是簡化Spring應用的搭建與開發過程
該框架開發人員不須要定義樣板化的配置
從根本上講,是一些庫的集合,構建項目,無須自行管理這些庫的版本

Spring Boot特色

建立獨立的Spring應用程序
嵌入的Tomcat,無須部署war文件
簡化Maven配置和Gradle配置
自動配置Spring
提供生產就緒功能,如指標、健康檢查和外部配置

Spring Boot使用場景

開發Restful風格的微服務架構
微服務、自動化、橫向擴展
精簡配置與整合其餘工具

4-2 項目搭建

建立名爲hotdeploy的gradle工程build.gradle腳本以下

buildscript {
    ext {
        springBootVersion = '1.5.6.RELEASE'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'

group = 'com.myimooc'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8

repositories {
    maven{ url "http://maven.aliyun.com/nexus/content/groups/public/"}
    mavenCentral()
}

dependencies {
    compile('org.springframework.boot:spring-boot-starter')
    compile('org.springframework.boot:spring-boot-starter-web')
    compile('org.springframework.boot:spring-boot-starter-data-jpa')
    compile('org.springframework.boot:spring-boot-starter-thymeleaf')
    compile('org.springframework.boot:spring-boot-devtools')
    compile('com.h2database:h2')
    
    testCompile('org.springframework.boot:spring-boot-starter-test')
}

代碼編寫

1.編寫HotDeployApplication類

package com.myimooc.hotdeploy;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;

/**
 * @title Spring Boot 熱啓動
 * @describe 啓動類
 * @author zc
 * @version 1.0 2017-12-01
 */
@SpringBootApplication
public class HotDeployApplication extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.run(HotDeployApplication.class, args);
    }
    
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(HotDeployApplication.class);
    }
}

2.編寫HotDeployController類

package com.myimooc.hotdeploy.web.controller;

import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

/**
 * @title 控制器
 * @describe 
 * @author zc
 * @version 1.0 2017-12-01
 */
@Controller
public class HotDeployController {
    
    // 等價於 @RequestMapping(value="/say",method=RequestMethod.GET)
    @GetMapping("/say")
    public String say(HttpServletRequest request){
        request.setAttribute("say", "Hello Spring Boot!");
        return "index";
    }
}

3.編寫index.html頁面

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Index</title>
</head>
<body>

<span th:text="${say}"></span>

</body>
</html>

4-3 部署實現

Spring Boot熱部署實現的方式

使用Spring Loaded:1.添加依賴,2.設置JVM參數
使用spring-boot-devtools:1.添加依賴

4-4 項目發佈

發佈方式

構建jar包,命令行運行Spring Boot程序
構建war包,發佈到Tomcat

第五章:課程總結

5-1 課程總結

課程總結

課程介紹
熱部署與熱加載
熱部署原理解析
Java類熱加載案例分析
Spring Boot簡單介紹
Spring Boot項目搭建
Spring Boot項目構建過程解析
Spring Boot熱部署的實現
Spring Boot發佈方式
相關文章
相關標籤/搜索