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

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】
免费领取10G资料包与项目实战视频资料

时间: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类的加载过程

2019101710049\_1.png

类加载的五个阶段

2019101710049\_2.png

Java类加载器特点

    1.由AppClassLoader(系统类加载器)开始加载指定的类
    2.类加载器将加载任务交给其父类,如果其父类找不到,再由自己去加载
    3.BootstrapLoader(启动类加载器)是最顶级的类加载器

Java类的热部署

    类的热加载
    配置Tomcat

通过类的热加载实现热部署

2019101710049\_3.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发布方式

来源:[]()

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » 慕课网_《Spring Boot热部署》学习总结

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏