PlayFrameworkhotswap及源码分析

play! ***的卖点就在于 hot swap,正如它自己宣称的:

创新互联坚持“要么做到,要么别承诺”的工作理念,服务领域包括:网站设计、网站建设、企业官网、英文网站、手机端网站、网站推广等服务,满足客户于互联网时代的新蔡网站设计、移动媒体设计的需求,帮助企业找到有效的互联网解决方案。努力成为您成熟可靠的网络建设合作伙伴!

reach your maximum productivity。play! 允许开发人员修改java文件,保存,然后刷新浏览器,立马可以看到效果。不需要编译,也不需要重启服务器。

Java 要想实现动态更新 class 文件,不外乎两种手段:替换 classloader、替换 JVM。因为替换 JVM 引起的开销更大,需要维护 JVM 的堆、栈等运行信息,所以 hot swap 通常是选择替换 classloader。比如 grails 里面就是选择替换 classloader,它会自己维护一个线程,定期轮询源文件是否发生修改,以替换原来的 classloader。那么 play! 宣称的 hot swap 又是怎么实现的呢?

让我们来看看play! 的内部流程:

1. play! 使用了 Apache Mina 作为底层的 http server,然后使用了自己关于 Mina IoHandler 接口的实现—— HttpHandler

2. 当浏览器发起一个 request:

2.1 Mina Server 生成一个 Mina Request,转发给 HttpHandler 的 messageReceived 方法

2.2 play! 解析 Mina Request 和 Mina Session,包装成自己的 Request 对象

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

2.3 play! 检测 Route 文件修改情况,根据 Route 配置信息将 Route/Action 的信息赋给 Request 对象

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

2.4 play! 根据当前配置的开发模式来采用不同的策略调用 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! 当前是 DEV 模式,invokeInThread方法会让 invocation 对象代理 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! 修改源文件后,刷新浏览器即见效的奥秘就在这里了。再进去看看 play! 自定义 classloader 的 detectChanges() 方法:

 
 
 
  1. public void detectChanges() {
  2. // Now check for file modification
  3. List modifieds = new ArrayList();
  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 newDefinitions = new ArrayList();
  11. Map annotationsHashes = new HashMap();
  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! 怎么实现 hot swap 的原理了,还是调用java.lang.instrument目录下的类和方法来实现的 hot swap。不存在魔法,play! 还是选择了替换 classloader,只不过这个替换动作发生在处理 http request 的时候,于是开发人员用起来就是“刷新浏览器就可以看见效果了”。

网站名称:PlayFrameworkhotswap及源码分析
地址分享:http://www.csdahua.cn/qtweb/news15/245215.html

网站建设、网络推广公司-快上网,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 快上网