Java對象序列化所引起的循環(huán)引用的思考

字號:

在Java中的模型關(guān)系設計中,循環(huán)的關(guān)系是很常見的,特別是ORM的出現(xiàn),關(guān)系的循環(huán)更加有利于維護各自的狀態(tài)。但就是這種循環(huán)的關(guān)系,在java對象序列化時,不可避免的會導致循環(huán)引用(Cycle Reference)的問題。
    導致CycleReference的情況
    還是舉個例子吧(代碼說話):一個很典型,很常見的雙向引用的對象關(guān)系。
    @Entity
    public class Company{
    @Id
    @Column(....)
    private String id;
    @OneToMany(....)
    private Employee employee;
    //setters/getters
    ......
    }
    @Entity
    public class Employee{
    @Id
    @Column(....)
    private String id;
    @ManyToOne
    private Company company;
    //setters/getters
    ......
    }
    另外一種導致這個問題的情況是,多個對象間關(guān)系形成一條回路,跟電學有點像。(具體就不舉例了,在模型設計時,還是避免出現(xiàn)這種情況。)
    導致這種問題的原因
    用jaxb(如果沒有特殊解釋,本文采用的都是jaxb)序列化Company時,無疑會發(fā)生循環(huán)引用。
    當序列化引擎解析Company時,它發(fā)現(xiàn)這個對象持有一個Employee的引用,轉(zhuǎn)而去騷擾Employee.解析Employee時,發(fā)現(xiàn)他又持有Company的引用,又轉(zhuǎn)回Company.如此問題產(chǎn)生。
    引擎它并不知道在遇到循環(huán)引用問題時,該怎么處理,它只是忠實得按照固定的算法去執(zhí)行任務。所以我們得讓引擎聰明點,我們得讓引擎遇到這種問題有處理機制。
    解決問題
    既然需要引擎更聰明,那就沒辦法,就得燒香拜佛,希望制造商的產(chǎn)品擴展性足夠好,考慮了足夠多的情況。
    幸運的是,jaxb提供了有這種擴展。(CycleRecoverable接口)
    行軍打仗(例子先行):(將以上的例子改下)
    @Entity
    public class Company implements CycleRecoverable{
    @Id
    @Column(....)
    private String id;
    @OneToMany(....)
    private Employee employee;
    //當遇到循環(huán)引用時,用temp替代this,返給jaxb解析。
    public Object onCycleDetected(Context arg0) {
    Company temp = new Company ();
    temp.setId(id);
    return temp;
    }
    //setters/getters
    ......
    }
    @Entity
    public class Employee implements CycleRecoverable{
    @Id
    @Column(....)
    private String id;
    @ManyToOne
    private Company company;
    public Object onCycleDetected(Context arg0) {
    Employee temp = new Employee();
    temp.setId(id);
    return temp;
    }
    //setters/getters
    ......
    }
    注意到onCycleDetected方法就是一個回調(diào)方法,當遇到循環(huán)引用時,jaxb引擎會調(diào)用這個方法,用return對象來替換this.所以在這個過程中,就可以將引起循環(huán)引用問題的關(guān)系斷開,返回給jaxb.
    當然Company和Employee對象沒必要全部實現(xiàn)CycleRecoverable接口,但是拿到現(xiàn)實的模型圖中去,誰也保證不了他們不跟別的對象有循環(huán)的關(guān)系存在。因此還是建議大家把模型都實現(xiàn)這個接口,也好一勞永逸。