自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Play Framework hotswap及源碼分析

開發(fā) 后端
reach your maximum productivity。play! 允許開發(fā)人員修改java文件,保存,然后刷新瀏覽器,立馬可以看到效果。不需要編譯,也不需要重啟服務(wù)器。

play! ***的賣點(diǎn)就在于 hot swap,正如它自己宣稱的:

reach your maximum productivity。play! 允許開發(fā)人員修改java文件,保存,然后刷新瀏覽器,立馬可以看到效果。不需要編譯,也不需要重啟服務(wù)器。

Java 要想實(shí)現(xiàn)動(dòng)態(tài)更新 class 文件,不外乎兩種手段:替換 classloader、替換 JVM。因?yàn)樘鎿Q JVM 引起的開銷更大,需要維護(hù) JVM 的堆、棧等運(yùn)行信息,所以 hot swap 通常是選擇替換 classloader。比如 grails 里面就是選擇替換 classloader,它會(huì)自己維護(hù)一個(gè)線程,定期輪詢?cè)次募欠癜l(fā)生修改,以替換原來的 classloader。那么 play! 宣稱的 hot swap 又是怎么實(shí)現(xiàn)的呢?

讓我們來看看play! 的內(nèi)部流程:

1. play! 使用了 Apache Mina 作為底層的 http server,然后使用了自己關(guān)于 Mina IoHandler 接口的實(shí)現(xiàn)—— HttpHandler

2. 當(dāng)瀏覽器發(fā)起一個(gè) request:

2.1 Mina Server 生成一個(gè) Mina Request,轉(zhuǎn)發(fā)給 HttpHandler 的 messageReceived 方法

2.2 play! 解析 Mina Request 和 Mina Session,包裝成自己的 Request 對(duì)象

  1. Request request = parseRequest(minaRequest, session);  

2.3 play! 檢測 Route 文件修改情況,根據(jù) Route 配置信息將 Route/Action 的信息賦給 Request 對(duì)象

  1. Router.detectChanges();  
  2. Router.route(request);  

2.4 play! 根據(jù)當(dāng)前配置的開發(fā)模式來采用不同的策略調(diào)用 Action 來理 Request

  1. if (Play.mode == Play.Mode.DEV) {  
  2. Invoker.invokeInThread(new MinaInvocation(session, minaRequest, minaResponse, request, response));  
  3. else {  
  4. Invoker.invoke(new MinaInvocation(session, minaRequest, minaResponse, request, response));  
  5. }  

2.5 如果 play! 當(dāng)前是 DEV 模式,invokeInThread方法會(huì)讓 invocation 對(duì)象代理 run() 方法

  1. public void run() {  
  2. try {  
  3. before();  
  4. execute();  
  5. after();  
  6. catch (Throwable e) {  
  7. onException(e);  
  8. finally {  
  9. _finally();  
  10. }  
  11. }  

咱們來看看 before() 方法:

  1. public static void before() {  
  2. Thread.currentThread().setContextClassLoader(Play.classloader);  
  3. if(!Play.id.equals("test")) {  
  4. Play.detectChanges();  
  5. if (!Play.started) {  
  6. Play.start();  
  7. }  
  8. }  
  9. //  
  10. }  

在 Play 類的 detectChanges() 方法里面,有這么一句:

  1. classloader.detectChanges();  

哈哈,play! 修改源文件后,刷新瀏覽器即見效的奧秘就在這里了。再進(jìn)去看看 play! 自定義 classloader 的 detectChanges() 方法:

  1. public void detectChanges() {  
  2. // Now check for file modification  
  3. List<ApplicationClass> modifieds = new ArrayList<ApplicationClass>();  
  4. for (ApplicationClass applicationClass : Play.classes.all()) {  
  5. if (applicationClass.timestamp < applicationClass.javaFile.lastModified()) {  
  6. applicationClass.refresh();  
  7. modifieds.add(applicationClass);  
  8. }  
  9. }  
  10. List<ClassDefinition> newDefinitions = new ArrayList<ClassDefinition>();  
  11. Map<Class, Integer> annotationsHashes = new HashMap<Class, Integer>();  
  12. for (ApplicationClass applicationClass : modifieds) {  
  13. annotationsHashes.put(applicationClass.javaClass, computeAnnotationsHash(applicationClass.javaClass));  
  14. if (applicationClass.compile() == null) {  
  15. Play.classes.classes.remove(applicationClass.name);  
  16. else {  
  17. applicationClass.enhance();  
  18. BytecodeCache.cacheBytecode(applicationClass.enhancedByteCode, applicationClass.name, applicationClass.javaSource);  
  19. newDefinitions.add(new ClassDefinition(applicationClass.javaClass, applicationClass.enhancedByteCode));  
  20. }  
  21. }  
  22. try {  
  23. HotswapAgent.reload(newDefinitions.toArray(new ClassDefinition[newDefinitions.size()]));  
  24. catch (ClassNotFoundException e) {  
  25. throw new UnexpectedException(e);  
  26. catch (UnmodifiableClassException e) {  
  27. throw new UnexpectedException(e);  
  28. }  
  29. // Check new annotations  
  30. for (Class clazz : annotationsHashes.keySet()) {  
  31. if (annotationsHashes.get(clazz) != computeAnnotationsHash(clazz)) {  
  32. throw new RuntimeException("Annotations change !");  
  33. }  
  34. }  
  35. // Now check if there is new classes or removed classes  
  36. int hash = computePathHash();  
  37. if (hash != this.pathHash) {  
  38. // Remove class for deleted files !!  
  39. for (ApplicationClass applicationClass : Play.classes.all()) {  
  40. if (!applicationClass.javaFile.exists()) {  
  41. Play.classes.classes.remove(applicationClass.name);  
  42. }  
  43. if(applicationClass.name.contains("$")) {  
  44. Play.classes.classes.remove(applicationClass.name);  
  45. }  
  46. }  
  47. throw new RuntimeException("Path has changed");  
  48. }  
  49. }  

HotswapAgent類的 reload 方法如下:

  1. public static void reload(ClassDefinition definitions) throws UnmodifiableClassException, ClassNotFoundException {  
  2. instrumentation.redefineClasses(definitions);  
  3. }  

讀到這里,也就弄清楚了 play! 怎么實(shí)現(xiàn) hot swap 的原理了,還是調(diào)用java.lang.instrument目錄下的類和方法來實(shí)現(xiàn)的 hot swap。不存在魔法,play! 還是選擇了替換 classloader,只不過這個(gè)替換動(dòng)作發(fā)生在處理 http request 的時(shí)候,于是開發(fā)人員用起來就是“刷新瀏覽器就可以看見效果了”。

原文鏈接:http://mingj.iteye.com/blog/307238

【編輯推薦】

  1. Play Framework總結(jié)性介紹
  2. 有可能挑戰(zhàn)Java優(yōu)勢的四種技術(shù)
  3. Think in Java之斐波那契數(shù)列
  4. Play Framework介紹:Hello World
  5. Play Framework介紹:主要概念
責(zé)任編輯:林師授 來源: mingj的博客
相關(guān)推薦

2012-02-23 11:06:18

JavaPlay FramewPlay!

2012-02-22 17:23:51

JavaPlay Framew

2012-02-23 13:13:00

JavaPlay Framew

2012-02-20 14:26:48

JavaPlay Framew

2012-02-24 09:53:24

JavaPlay Framew

2012-03-14 09:29:00

Play framewJava

2012-02-23 13:48:16

JavaPlay Framew

2012-02-20 14:20:44

JavaPlay Framew

2012-03-14 12:29:55

JavaPlay Framwo

2012-02-22 16:06:42

2012-02-24 10:57:43

2012-02-24 11:31:09

JavaPlay Framew

2012-02-20 14:41:30

JavaPlay Framew

2023-01-10 07:52:15

2021-08-09 11:15:28

MybatisJavaSpring

2012-02-29 10:54:21

JavaPlay Framew

2011-09-09 17:01:42

框架

2021-04-28 06:26:11

Spring Secu功能實(shí)現(xiàn)源碼分析

2015-11-23 09:50:15

JavaScript模塊化SeaJs

2019-10-16 16:33:41

Docker架構(gòu)語言
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)