Playframework 热代码替换是否可用?
我来自Tomcat的背景,它有一个很好的特性,叫做“热代码替换”——它可以在运行的web应用程序中替换Java代码,而不会干扰现有的HTTP会话/初始化对象 最近我开始学习Play framework,虽然它确实进行“代码替换”,但它似乎可以重新启动整个应用程序,而不仅仅是替换更改的代码,因此所有Java对象/静态变量/HTTP会话都会丢失Playframework 热代码替换是否可用?,playframework,Playframework,我来自Tomcat的背景,它有一个很好的特性,叫做“热代码替换”——它可以在运行的web应用程序中替换Java代码,而不会干扰现有的HTTP会话/初始化对象 最近我开始学习Play framework,虽然它确实进行“代码替换”,但它似乎可以重新启动整个应用程序,而不仅仅是替换更改的代码,因此所有Java对象/静态变量/HTTP会话都会丢失 Tomcat的热代码替换功能(或类似功能)在游戏中可用吗?如评论中所述,游戏设计为无状态,因此不需要这样的功能。使用会话将数据存储在客户机上,在重新加载代码
Tomcat的热代码替换功能(或类似功能)在游戏中可用吗?如评论中所述,游戏设计为无状态,因此不需要这样的功能。使用会话将数据存储在客户机上,在重新加载代码后数据肯定可用使用安全的Cookie,以防被秘密密钥操纵 如果在会话中存储数据不适用(因为它的大小或因为它被多个客户端全局使用),请使用。诀窍是使缓存中的任何内容都可以恢复,以防由于某种原因丢失(例如在您的情况下重新启动) 对于缓存中存储的任何数据,都需要制定一个再生策略,以防数据丢失。这一理念是Play背后的基础之一,与JavaEE不同,JavaEE期望会话在其整个生命周期中保持价值 我认为Play(仅适用于1.x branch)无状态的主要原因是避免在服务器中以任何形式使用“会话”状态(http会话、静态变量等),因为我认为这有助于简化可伸缩性,但您可以在客户端的加密cookie中使用“登录”状态(随每个http请求一起发送到服务器),对于身份验证,我认为这就足够了,如果需要用户数据,只需再次查询数据库(对于简单字符串,也可以将它们存储在会话中) 无论如何,如果您想在整个应用程序生命周期中“保留”服务器端的某些全局状态,请使用
@OnApplicationStop
序列化当前状态(静态变量、某些对象)并@OnApplicationStart
再次加载,此机制与播放开发模式的“代码替换”兼容:)
大概是这样的:
SomeObject.java
package util;
import java.io.Serializable;
public class SomeObject implements Serializable {
public String someAttribute;
}
package util;
public class ClassWithStaticState {
public static SomeObject someStateObject;
}
package util;
@OnApplicationStop
public class StatePreserver extends Job {
@Override
public void doJob() throws Exception {
new ObjectOutputStream(new FileOutputStream("preservedstate.bin")).writeObject(ClassWithStaticState.someStateObject);
}
}
package util;
@OnApplicationStart
public class StateLoader extends Job {
@Override
public void doJob() throws Exception {
File file = new File("preservedstate.bin");
SomeObject someObject;
if (file.exists()) {
someObject = (SomeObject) new ObjectInputStream(new FileInputStream(file)).readObject();
} else {
someObject = new SomeObject();
someObject.someAttribute = "hey!"; // attribute can be modified at runtime but will be preserved across Play development modifications
}
ClassWithStaticState.someStateObject = someObject;
}
}
ClassWithStaticState.java
package util;
import java.io.Serializable;
public class SomeObject implements Serializable {
public String someAttribute;
}
package util;
public class ClassWithStaticState {
public static SomeObject someStateObject;
}
package util;
@OnApplicationStop
public class StatePreserver extends Job {
@Override
public void doJob() throws Exception {
new ObjectOutputStream(new FileOutputStream("preservedstate.bin")).writeObject(ClassWithStaticState.someStateObject);
}
}
package util;
@OnApplicationStart
public class StateLoader extends Job {
@Override
public void doJob() throws Exception {
File file = new File("preservedstate.bin");
SomeObject someObject;
if (file.exists()) {
someObject = (SomeObject) new ObjectInputStream(new FileInputStream(file)).readObject();
} else {
someObject = new SomeObject();
someObject.someAttribute = "hey!"; // attribute can be modified at runtime but will be preserved across Play development modifications
}
ClassWithStaticState.someStateObject = someObject;
}
}
StatePreserver.java
package util;
import java.io.Serializable;
public class SomeObject implements Serializable {
public String someAttribute;
}
package util;
public class ClassWithStaticState {
public static SomeObject someStateObject;
}
package util;
@OnApplicationStop
public class StatePreserver extends Job {
@Override
public void doJob() throws Exception {
new ObjectOutputStream(new FileOutputStream("preservedstate.bin")).writeObject(ClassWithStaticState.someStateObject);
}
}
package util;
@OnApplicationStart
public class StateLoader extends Job {
@Override
public void doJob() throws Exception {
File file = new File("preservedstate.bin");
SomeObject someObject;
if (file.exists()) {
someObject = (SomeObject) new ObjectInputStream(new FileInputStream(file)).readObject();
} else {
someObject = new SomeObject();
someObject.someAttribute = "hey!"; // attribute can be modified at runtime but will be preserved across Play development modifications
}
ClassWithStaticState.someStateObject = someObject;
}
}
StateLoader.java
package util;
import java.io.Serializable;
public class SomeObject implements Serializable {
public String someAttribute;
}
package util;
public class ClassWithStaticState {
public static SomeObject someStateObject;
}
package util;
@OnApplicationStop
public class StatePreserver extends Job {
@Override
public void doJob() throws Exception {
new ObjectOutputStream(new FileOutputStream("preservedstate.bin")).writeObject(ClassWithStaticState.someStateObject);
}
}
package util;
@OnApplicationStart
public class StateLoader extends Job {
@Override
public void doJob() throws Exception {
File file = new File("preservedstate.bin");
SomeObject someObject;
if (file.exists()) {
someObject = (SomeObject) new ObjectInputStream(new FileInputStream(file)).readObject();
} else {
someObject = new SomeObject();
someObject.someAttribute = "hey!"; // attribute can be modified at runtime but will be preserved across Play development modifications
}
ClassWithStaticState.someStateObject = someObject;
}
}
有关这些注释的一些解释,请参见此处
实际上,我认为Play没有序列化,而是使用了
Play.cache.cache
来代替这些示例中的序列化 哼。Play被设计为无状态,没有服务器状态。您是否将自己的状态存储在服务器上以进行身份验证?@JulienLafont大多数web程序都有登录过程。使用Tomcat和Java,我再也不用登录就能看到新代码的出现。重装代码时,Play framework似乎完全不保留会话信息。“重装代码时,Play framework似乎完全不保留会话信息”。是的,当类被重新加载时JVM被重置。这通常不是问题,因为游戏被认为是完全无状态的。您可以使用无状态服务器进行登录。一切都在你的饼干里。您是在服务器上存储另一个数据,还是只使用会话机制?使用Tomcat,我的J2EE应用程序可以有任何状态信息(无论是会话信息、静态变量还是任何对象),重新加载的类不会破坏任何状态信息。这种行为(或类似行为)在游戏中可用吗?这是否意味着在代码替换期间/之后没有办法保留静态变量值?这听起来太奇怪了,不可能是真的。如果我的应用程序需要10分钟才能启动,我就不应该再等10分钟,只为Play应用一个小的代码更改。@HowardGuo我只是不知道任何方法。不过仍然有一些方法可以实现——afaik Play可以在Tomcat中运行,是否可以使用它来代替集成的Play服务器?除此之外,10分钟的创业时间听起来也很奇怪。如果可能的话,我会让所有的初始化都变得懒惰,这在缓存方法中起到了很好的作用。当然,也可能是Play不是该架构的合适工具。