Java循环引用

时间:2012-05-14 09:22:31

标签: java constructor stack-overflow circular-reference

在我正在进行的项目中,人们编写了服务类来访问DAO。 几乎每个业务对象都有自己的服务,使用它自己的DAO。 在某些服务上,我们使用对其他服务的引用。 目前,人们正在构造函数中实例化所需的服务。

但是现在,我遇到了麻烦,因为服务A需要服务B而服务B需要服务A所以调用任何一个构造函数都会导致堆栈溢出......

示例(伪代码):

//Constructor of OrderService
public OrderService() {
     orderDAO = DAOFactory.getDAOFactory().getOrderDAO();
     itemService = new ItemService();
}

//Constructor of ItemService
public ItemService() {
     itemDAO = DAOFactory.getDAOFactory().getItemDAO();
     orderService = new OrderService();
}

你会如何解决这个问题?使用单身模式?

由于

4 个答案:

答案 0 :(得分:4)

Spring Framework通过使用依赖注入解决了这个问题。简而言之,它的作用是实例化所有DAO,然后在实例化之后但在主业务逻辑之前设置dao-dependencies。

如果您必须手动执行此操作,请参阅以下示例:

/*
  OrderService
 */
public OrderService ()
{
     orderDAO = DAOFactory.getDAOFactory().getOrderDAO();
}

public setItemService (ItemService service)
{
     itemService = service;
}

/*
  ItemService
 */
public ItemService ()
{
     itemDAO = DAOFactory.getDAOFactory().getItemDAO();
}

public setOrderService (OrderService service)
{
     orderService = service;
}

/*
   Bring it together in some other class
 */
...
// instantiate singletons
orderService = new OrderService ();
itemService = new ItemService ();

// inject dependencies
orderService.setItemService (itemService);
itemService.setOrderService (orderService);

答案 1 :(得分:1)

让OrderService只使用订单执行操作。让ItemService只对项目做事。然后创建一个OrderItemService,它将两者结合起来。

答案 2 :(得分:0)

是的,“单例模式”和延迟初始化都可以。不要在构造函数中初始化服务,而是在静态getter中初始化:

class OrderService {
  private static OrderService instance;
  private OrderDAO orderDAO;

  public OrderService() {
    orderDAO = DAOFactory.getDAOFactory().getOrderDAO();
  }

  public static synchronized OrderService getInstance() {
    if (instance == null) {
      instance = new OrderService();
    }

    return instance;
  }
}

作为Jonathan stated,您还可以将服务注入其他服务,但可能不需要。如果同步容易导致内存问题,则可以使用volatile解决此问题。另请参阅this answer here,详细说明“双重检查锁定模式”(尽管如此,要小心!)

答案 3 :(得分:0)

你能从构造函数中分离出“服务”吗?

或者换句话说,假设您有一个OrderService,它需要查阅自己的ItemService个人副本。这个ItemService实例是否需要它的自己的OrderService副本来满足OrderService调用它的请求?

因此,它将是一种懒惰的初始化 - 除非你真正需要它,否则不要创建新项目。除非您需要,否则不要链接其他服务。

第二个想法:你可以将副本作为构造函数的一部分传递吗?

e.g:

//Constructor of OrderService public OrderService() 
{     orderDAO = DAOFactory.getDAOFactory().getOrderDAO();
      itemService = new ItemService(this); 
}
//Constructor of ItemService public ItemService(OrderService orderService) 
{     itemDAO = DAOFactory.getDAOFactory().getItemDAO();
      this.orderService = orderService; 
}

还是可能反向?