小编典典

如何序列化注入的bean?

java

我想以各种时间间隔保存注入的有状态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,但是我正在尝试核心序列化。

使用JavaEE7和Wildfly 10.1。


阅读 256

收藏
2020-11-30

共1个答案

小编典典

由于各种原因,直接序列化CDI bean很危险:

  • 您可能有一个代理,而不是实际的对象。对于该对象的依赖关系也是如此
  • 序列化意味着将一次对数据进行反序列化。但是CDI bean是由CDI管理的,CDI无法将反序列化的对象“附加”到其托管对象集中。

但是,此问题的目的是以某种方式保存CDI bean的状态,以便以后可以将其还原。这可以通过使用另一个保存CDI
bean状态的对象来实现。该其他对象不受CDI管理,即由创建new,并且可序列化。每个需要保持其状态的CDI
bean都有一对setState(state)/ getState()方法-
它们甚至可以是接口的一部分。你可能希望每个对象传播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以处理不透明的对象:

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;
    }
2020-11-30