如何序列化注入的bean? [英] How to serialize an injected bean?

查看:121
本文介绍了如何序列化注入的bean?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想以不同的间隔保存注入的有状态bean的数据:更改 - 保存 - 更改 - 保存...我正在使用核心序列化,问题是所有字节数组都是相同的。我相信代理是序列化的,因为如果我稍后反序列化其中一个数组,我会获得bean的当前状态。

I would like to save the data of an injected stateful bean at various intervals: change - save - change- save... I'm using core serialization and the problem is that all the byte arrays are the same. i believe the proxy is serialized because if I deserialize one of the arrays later I get the current state of the bean.

序列化的示例没有捕获bean中的更改:

Example of serialization not capturing changes in the 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类:

And this is a JAX-RS class:

@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;
    }
}

我想要做的只是保存列表因为这是相关数据。我也尝试过JSON序列化,它给出了一个 IOException ,但我正在尝试核心序列化。

What I want to do is only save the list in State as that's the relevant data. I also tried JSON serialization and it gave an IOException, but I'm trying core serialization.

使用JavaEE7和Wildfly 10.1。

Using JavaEE7 and Wildfly 10.1.

推荐答案

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

For various reasons, serializing a CDI bean directly is dangerous:


  • 您可能有代理,而不是实际对象;同样适用于该对象的依赖关系

  • 序列化意味着数据将一次反序列化。但CDI bean由CDI管理,CDI无法将反序列化对象附加到其托管对象集中。

但是这个问题的目的是以某种方式保存CDI bean的状态,以便以后可以恢复。这可以通过使用另一个保存CDI bean状态的对象来完成。此其他对象不由CDI管理,即使用 new 创建,并且是可序列化的。需要保持其状态的每个CDI bean都有一对 setState(state) / getState()方法 - 它们甚至可以成为界面的一部分。您可能希望每个对象也向其协作者传播 setState(state) / getState()

But the purpose of this question is to somehow save the state of a CDI bean in a way that it can be restored later. This can be accomplished by using another object that holds the state of the CDI bean. This other object is not managed by CDI, i.e. created with new, and is serializable. Each CDI bean that needs to persist its state has the pair of setState(state)/getState() methods - they could even be part of an interface. You probably want each object to propagate setState(state)/getState() to its collaborators too.

请参阅 Memento 设计模式。如果您熟悉它,也可以在JSF状态保存/恢复机制中实现。

See the Memento design pattern. This is also implemented in the JSF state saving/restoring mechanism, if you are familiar with it.

一些示例代码(还有其他有效的方法),从状态界面开始:

Some example code (there are other valid ways to do it), starting with the state interface:

interface HasState<S extends Serializable> {
    S getState();
    void setState(S state);
}

然后服务本身,有一个协作者,以及相关的状态对象:

Then the service itself, that has a collaborator, and the relevant state object:

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());
    }
}

协作者及其状态遵循相同的模式:

The collaborator and its state follow the same pattern:

class CollaboratorState implements Serializable {
    private String anyName;
    // accessors
}

@RequestScoped
class Collaborator implements HasState<CollaboratorState> {
    // you get the point...
}

示例用法,遵循问题中的代码:

And an example usage, following the code from the question:

@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 来处理不透明的对象:


If the client of a service needs to know that a service has state, then the client and service might be more coupled than it would be desired. A way out is to modify HasState to deal with opaque objects:

interface HasState {
    Object getState();
    void setState(Object state);
}

客户端的状态包含每个协作者状态的列表:

The state of the client contains a list for the state of each collaborator:

class SomeServiceState implements Serializable {
    private String someData;
    private Long someId;
    private List<String> list;
    private List<Object> collaboratorsState;
    // accessors
}

客户端仅向州政府添加协作者如果它扩展 HasState

The client adds a collaborator to the state only if it extends 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;
    }

这篇关于如何序列化注入的bean?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆