時間:2017年12月01日星期五
說明:本文部份內容均來自慕課網。@慕課網:http://www.imooc.com
教學源碼:無
學習源碼:https://github.com/zccodere/s...html
熱部署的使用場景java
本地調式 線上發佈
熱部署的使用優勢git
不管本地仍是線上,都適用 無需重啓服務器:提升開發、調式效率、提高發布、運維效率、下降運維成本
前置知識github
掌握Java語言 有必定的Spring開發經驗 掌握構建Spring Boot項目的方法
課程提綱web
原理解析 案例分析 項目演示 測試驗證 發佈程序 課程總結
Java熱部署與熱加載聯繫spring
不重啓服務器編譯或部署項目 基於Java的類加載器實現
Java熱部署與熱加載的區別設計模式
部署方式 --熱部署在服務器運行時從新部署項目 --熱加載在運行時從新加載class 實現原理 --熱部署直接從新加載整個應用 --熱加載在運行時從新加載class 使用場景 --熱部署更多的是在生產環境使用 --熱加載則更多的是在開發環境使用
Java類的加載過程tomcat
類加載的五個階段服務器
Java類加載器特色架構
1.由AppClassLoader(系統類加載器)開始加載指定的類 2.類加載器將加載任務交給其父類,若是其父類找不到,再由本身去加載 3.BootstrapLoader(啓動類加載器)是最頂級的類加載器
Java類的熱部署
類的熱加載 配置Tomcat
經過類的熱加載實現熱部署
經過配置Tomcat實現熱部署
1.直接把項目web文件夾放在webapps裏 2.在tomcat/conf/server.xml中的<host></host>內部添加<context/>標籤 3.在%tomcat_home%/conf/Catalina/localhost中添加一個XML
寫一個Java類熱加載的實際案例,要求以下
1.類層次結構清晰,修改某一個Java類文件不須要重啓服務或者從新編譯運行程序 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(); } }
Spring Boot簡單介紹
是一個全新框架,目的是簡化Spring應用的搭建與開發過程 該框架開發人員不須要定義樣板化的配置 從根本上講,是一些庫的集合,構建項目,無須自行管理這些庫的版本
Spring Boot特色
建立獨立的Spring應用程序 嵌入的Tomcat,無須部署war文件 簡化Maven配置和Gradle配置 自動配置Spring 提供生產就緒功能,如指標、健康檢查和外部配置
Spring Boot使用場景
開發Restful風格的微服務架構 微服務、自動化、橫向擴展 精簡配置與整合其餘工具
建立名爲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>
Spring Boot熱部署實現的方式
使用Spring Loaded:1.添加依賴,2.設置JVM參數 使用spring-boot-devtools:1.添加依賴
發佈方式
構建jar包,命令行運行Spring Boot程序 構建war包,發佈到Tomcat
課程總結
課程介紹 熱部署與熱加載 熱部署原理解析 Java類熱加載案例分析 Spring Boot簡單介紹 Spring Boot項目搭建 Spring Boot項目構建過程解析 Spring Boot熱部署的實現 Spring Boot發佈方式