为了账号安全,请及时绑定邮箱和手机立即绑定

慕课网《Spring Boot热部署》学习总结

标签:
Java

慕课网《Spring Boot热部署》学习总结

时间:2017年12月01日星期五
说明:本文部分内容均来自慕课网。@慕课网:http://www.imooc.com 
教学源码:无 
学习源码:https://github.com/zccodere/study-imooc
第一章:课程介绍
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发布方式
点击查看更多内容
3人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
JAVA开发工程师
手记
粉丝
138
获赞与收藏
532

关注作者,订阅最新文章

阅读免费教程

感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消