时间: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发布方式