spring boot入門之——熱部署

場景:java

  • 本地調試(頻繁的啓動/中止服務器)web

  • 線上發佈(每次都須要啓動/中止服務器)tomcat


優勢:服務器

  • 不管本地仍是線上,都適用app

  • 無需重啓服務器,提升開發、調試效率;提高發布、運維效率,下降運維成本運維

BaiduShurufa_2018-6-17_14-0-33.jpg

1、java實現熱部署有哪幾種方式?webapp

  • 經過配置tomcat,直接把項目放在webapps裏。jvm

  • 在tomcat\conf\server.xml中的<host></host>中添加<context debug="0" docBase="" path="" privileged="true" reloadable="true"/>標籤ide

  • 在tomcat\conf\Catalina\localhost中添加xml,關鍵屬性<context docBase="" reloadable="true" />測試


BaiduShurufa_2018-6-17_14-0-33.jpg

實現一個Java類熱加載的實例

1.定義類加載器

//自定義類加載器,需實現findClass方法(核心類)
public class MyClassLoader extends ClassLoader {
	
	//定義加載的路徑
	private String classPath;
	
	public MyClassLoader(String classPath) {
		//調用父類的加載器
		super(ClassLoader.getSystemClassLoader());
		this.classPath = classPath;
	}

	//1.從新findClass方法
	@Override
	protected Class<?> findClass(String name) throws ClassNotFoundException {
		byte[] b = this.loadData(name);
		return this.defineClass(name, b, 0, b.length);
	}

	//加載class文件中的內容
	private byte[] loadData(String name) {
		//.替換爲//表示
		name = name.replaceAll(".", "//");
		try {
			FileInputStream is = new FileInputStream(new File(classPath + name + ".class"));
			ByteArrayOutputStream aos = new ByteArrayOutputStream();
			int b = 0;
			while((b = is.read())!=-1){
				aos.write(b);
			}
			is.close();
			aos.close();
			return aos.toByteArray();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return null;
	}
}


2.實現熱加載的功能(即:哪些方法被熱加載了,能夠動態更新)

//該子類下的須要動態更新
public interface BaseManager {

	public void logic();
}
//實現具體的熱加載功能
public class MyManager implements BaseManager{

	@Override
	public void logic() {
		System.out.println("熱加載:logic...");
		
	}
}


3.定義封裝類,定義須要加載的信息

public class LoadInfo {

	private MyClassLoader loader;
	
	//(起一個線程)記錄要加載的類的時間戳-->加載的時間
	private long loadTime;
	
	private BaseManager manager;

	public LoadInfo(MyClassLoader loader, long loadTime) {
		super();
		this.loader = loader;
		this.loadTime = loadTime;
	}
	//get、set方法
	
}


4.創建工廠類,加載manager

//加載manager的工廠
public class ManagerFactory {

	//記錄熱加載類的加載信息
	private static final Map<String, LoadInfo> loadTimeMap = 
			new HashMap<>();
	
	//要加載類的classpath
	private static final String CLASS_PATH = "E:/workspace/class_loader/bin";
	
	//實現熱加載的類的全名稱(包名+類名)
	public static final String MY_MANAGER = "class_loader.MyManager";
	
	public static BaseManager getManager(String className){
		File loadFile = new File(CLASS_PATH+className.replaceAll("\\.", "/")+".class");
		//取的最後一次的修改時間
		long lastModified = loadFile.lastModified();
		//loadTimeMap不包含className爲key的LoadInfo信息,證實這個類沒有被加載,那麼須要加載這個類到jvm
		if (loadTimeMap.get(className) == null) {
			load(className,lastModified);
		//加載類的時間戳變化了,一樣須要從新加載這個類到jvm
		}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.loadClass(className);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		BaseManager manager = newInstance(loadClass);
		LoadInfo loadInfo = new LoadInfo(myClassLoader, lastModified);
		loadInfo.setManager(manager);
		loadTimeMap.put(className, loadInfo);
	}

	//以反射的方式建立BaseManager子類對象
	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;
	}
}


5.檢測修改過的class

//後臺啓動一個線程不斷刷新從新加載實現熱加載的類
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();
			}
		}
	}
}


6.測試

public class ClassLoaderTest {

	public static void main(String[] args) {
		new Thread(new MsgHandler()).start();
	}
}

運行Test,結果以下:

BaiduShurufa_2018-6-17_14-0-33.jpg


2、Spring Boot怎麼實現熱部署?

實現方式有兩種

  • 使用Spring Loaded

  • 使用Spring-boot-devtools


第一種:

BaiduShurufa_2018-6-17_14-0-33.jpg


第二種:

BaiduShurufa_2018-7-1_17-46-5.jpg

相關文章
相關標籤/搜索