加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

采用CXF解决webservice循环引用对象的问题

发布时间:2020-12-17 00:21:15 所属栏目:安全 来源:网络整理
导读:本文讨论的是在cxf下如何解决webservice中存在对象循环引用的问题 不说明cxf的用法和spring整合等等,这在官方文档里都有. 循环引用: Parent 和 Child是1:n的关系,Parent含有一个child的列表children,child对于parent有一个引用,那这两个对象之间就存在循环引
本文讨论的是在cxf下如何解决webservice中存在对象循环引用的问题
不说明cxf的用法和spring整合等等,这在官方文档里都有.

循环引用:
Parent 和 Child是1:n的关系,Parent含有一个child的列表children,child对于parent有一个引用,那这两个对象之间就存在循环引用的关系.
java 代码
  1. public class Parent {?
  2. ??? private List children;?
  3. ?????
  4. ??? // setter / getter?
  5. }?

java 代码
java 代码
  1. import javax.xml.bind.annotation.XmlTransient;???
  2. ????
  3. public class Child {???
  4. ??? private Parent parent;???
  5. ????????
  6. ??? @XmlTransient???
  7. ??? public Parent getParent() {???
  8. ??????? return parent;???
  9. ??? }???
  10. ????
  11. ??? public void setParent(Parent parent) {???
  12. ??????? this.parent = parent;???
  13. ??? }??
  14. ?????
  15. ??? public void afterUnmarshal(Unmarshaller u,Object parent) {?
  16. ??????? this.parent = (Parent) parent;?
  17. ??? }???
  18. }???


这就是一个典型的环引用,而我们不能 直接将带有环的对象暴露给webservice,因为这会导致最终生成xml的时候会陷入死循环最后栈溢出,所以cxf检测出对象存在cycle会抛出一 个异常阻止进一步发布webservice.(以前的XFire可没这么聪明,它没有检测机制,直接就去序列化xml结果会导致 OutOfMemory).

如何解决呢?就是要破掉这个环,去某一端,如何在不破坏原有设计的情况下做到这一点,就是要使用@XmlTransient
这个annotation会标明这个字段不要解析成xml,所有你不想解析进webservice的都可以通过这个标签来标记
注:cxf默认采用JAXB做databindings,如果要用aegis,相应的就要用@IgnoreProperty这个元注释
像这种情况,我们一般要打破子对父的引用,就是要打破Child对于Parent的引用.注意要在parent的get方法上面加而不是在parent的声明处.
这样从生成的wsdl里面我们就看不到child里有对于parent的引用

虽然client能够拿到children列表了,但通过child得不到parent的信息,因为在client现在是单向的,那我也想访问parent怎么办?
这里有一个解决办法,在Parent下面加入如下代码:
??? public void afterUnmarshal(Unmarshaller u,Object parent) {
??????? this.parent = (Parent) parent;
??? }

怎么做到的?背后的道理是这样的:
循环的双向关系,一端到另一端的关系确定了以后,反过来另一端也就确定了.
cxf在解析wsdl映射成对象的过程中(也就是unmarshal),处理Parent并处理它所包含的child,结果发现parent引 用的child有afterUnmarshal方法,然后把自己的引用通过该方法传递给child,这样child也具有了对于 parent的引用,这一切都是在客户端完成的.真的是很聪明的做法.

这些功能必须要cxf来做客户端才能实现,但我们可以利用这种技术来在其他客户端实现这个功能.比如flex,.net,php 等等.

one more thing

上面的例子首先访问的是parent,cxf可以拿到两端的信息,但如果先访问child就拿不到parent了. 那么如果把@XmlTransient加到Parent,同样道理,child可以得到parent的信息,但是这个parent的getChildren里恐怕就只有那一个child了. 所以还是看具体设计,如果parent需要经常访问child,第一种最好,如果child要经常访问parent,显然是第二种

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读