我想以各种时间间隔保存注入的有状态bean的数据:更改-保存- 更改保存…我正在使用核心序列化,问题是所有字节数组都相同。我相信代理是序列化的,因为如果以后反序列化其中一个数组,则会得到Bean的当前状态。
序列化示例未捕获Bean中的更改:
@Stateful @RequestScoped public class State implements Serializable { private static final long serialVersionUID = 1L; @Inject StatelessBean bean; // assume it's needed private List<String> list = new ArrayList<>(); public void add() { list.add("S"); } }
这是一个JAX-RS类:
@Stateless @Path("t1") public class ChickensResource { @Inject State state; @GET @Path("/test") public String test() { state.add(); byte[] b0 = serialize(state); System.out.println(b0.length + " " + Arrays.toString(b0)); state.add(); byte[] b1 = serialize(state); System.out.println(b1.length + " " + Arrays.toString(b1)); // prints same as b0 System.out.println(b0.length + " " + Arrays.toString(b0)); // prints same thing } public static <T extends Serializable> byte[] serialize(T s) { try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos)) { oos.writeObject(s); return bos.toByteArray(); } catch (IOException e) { e.printStackTrace(); } return null; } }
我要做的只是将列表保存在其中,State因为这是相关数据。我还尝试了JSON序列化,并且给出了IOException,但是我正在尝试核心序列化。
State
IOException
使用JavaEE7和Wildfly 10.1。
由于各种原因,直接序列化CDI bean很危险:
但是,此问题的目的是以某种方式保存CDI bean的状态,以便以后可以将其还原。这可以通过使用另一个保存CDI bean状态的对象来实现。该其他对象不受CDI管理,即由创建new,并且可序列化。每个需要保持其状态的CDI bean都有一对setState(state)/ getState()方法- 它们甚至可以是接口的一部分。你可能希望每个对象传播setState(state)/ getState()它的合作者了。
new
setState(state)
getState()
请参阅Memento设计模式。如果您熟悉它,也可以在JSF状态保存/恢复机制中实现。
从状态接口开始的一些示例代码(还有其他有效的方法):
interface HasState<S extends Serializable> { S getState(); void setState(S state); }
然后是具有协作者的服务本身,以及相关的状态对象:
class SomeServiceState implements Serializable { private String someData; private Long someId; private List<String> list; private CollaboratorState collaboratorState; // accessors } @RequestScoped public class SomeService implements HasState<SomeServiceState> { // COLLABORATORS @Inject Collaborator collaborator; // assume it's needed // INTERNAL STATE private String someData; private Long someId; private List<String> list = new ArrayList<>(); public void add() { list.add("S"); } // ... public SomeServiceState getState() { SomeServiceState state = new SomeServiceState(); state.setSomeData(someData); state.setSomeId(someId); state.setList(new ArrayList<>(list)); // IT IS PROBABLY SAFER TO COPY STATE! // SEE HOW STATE GETS EXTRACTED RECURSIVELY: state.setCollaboratorState(collaborator.getState()); return state; } public void setState(SomeServiceState state) { someData = state.getSomeData(); someId = state.getSomeId(); list = new ArrayList<>(state.getList()); // SEE HOW STATE GETS APPLIED RECURSIVELY: collaborator.setState(state.getCollaboratorState()); } }
合作者及其状态遵循相同的模式:
class CollaboratorState implements Serializable { private String anyName; // accessors } @RequestScoped class Collaborator implements HasState<CollaboratorState> { // you get the point... }
以及示例用法,遵循问题中的代码:
@Stateless @Path("t1") public class ChickensResource { @Inject SomeService someService; @GET @Path("/test") public String test() { someService.add(); byte[] b0 = serialize(someService.getState()); // ... } public static <T extends Serializable> byte[] serialize(T s) { try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos)) { oos.writeObject(s); return bos.toByteArray(); } catch (IOException e) { e.printStackTrace(); } return null; } }
编辑:如果服务的客户端需要知道服务具有状态,则客户端和服务可能比期望的耦合得多。一种解决方法是修改HasState以处理不透明的对象:
HasState
interface HasState { Object getState(); void setState(Object state); }
客户端的状态包含每个协作者的状态的列表:
class SomeServiceState implements Serializable { private String someData; private Long someId; private List<String> list; private List<Object> collaboratorsState; // accessors }
客户端仅在扩展时将协作者添加到状态HasState:
public Object getState() { SomeServiceState state = new SomeServiceState(); state.setSomeData(someData); state.setSomeId(someId); state.setList(new ArrayList<>(list)); if( collaborator instanceof HasState ) { state.getCollaboratorsState().add(collaborator.getState()); } return state; }