时间:2017年12月01日星期五
说明:本文部分内容均来自慕课网。@慕课网:http://www.imooc.com
教学源码:无
学习源码:https://github.com/zccodere/s…
第一章:课程介绍
1-1 课程介绍
热部署的使用场景
本地调式
线上发布
热部署的使用优点
无论本地还是线上,都适用
无需重启服务器:提高开发、调式效率、提升发布、运维效率、降低运维成本
前置知识
掌握Java语言
有一定的Spring开发经验
掌握构建Spring Boot项目的方法
课程提纲
原理解析
案例分析
项目演示
测试验证
发布程序
课程总结
第二章:原理解析
2-1 部署加载
Java热部署与热加载联系
不重启服务器编译或部署项目
基于Java的类加载器实现
Java热部署与热加载的区别
部署方式
--热部署在服务器运行时重新部署项目
--热加载在运行时重新加载class
实现原理
--热部署直接重新加载整个应用
--热加载在运行时重新加载class
使用场景
--热部署更多的是在生产环境使用
--热加载则更多的是在开发环境使用
2-2 原理解析
Java类的加载过程
类加载的五个阶段
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
第三章:案例分析
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发布方式