8

我刚刚在读这篇文章:

http://www.tutorialized.com/view/tutorial/Spring-MVC-Application-Architecture/11986

我觉得很棒。它很好地解释了层架构,我很高兴我正在使用的架构几乎就是他所描述的。

但有一件事,我似乎没有得到:

第一:究竟什么是业务逻辑,什么不是?他在文章中说(而且他不是唯一一个),业务逻辑应该放在领域模型中。所以一个Account类应该有一个activate()知道如何激活Account. 据我了解,这可能涉及一些持久性工作。但是领域模型不应该依赖于 DAO。只有服务层应该知道 DAO。

那么,业务逻辑是否只是领域实体可以对自身做的事情?就像该activate()方法将active属性设置为true,再加上将属性设置dateActivatednew Date(),然后服务的任务是首先调用account.activate()和第二个dao.saveAccount(account)?服务需要什么外部依赖项?这就是我到目前为止所做的大部分工作。

public AccountServiceImpl implements AccountService
{
  private AccountDAO dao;
  private MailSender mailSender;

  public void activateAccount(Account account)
  {
     account.setActive(true);
     account.setDateActivated(new Date());
     dao.saveAccount(account);
     sendActivationEmail(account);
  }
  private void sendActivationEmail(Account account)
  {
    ...
  }
}

这与他所说的相反,我想,不是吗?

我也没有得到关于如何拥有 Spring 线域对象的示例,例如Account. 如果 Account 自己发送电子邮件,则需要这样做。

鉴于此代码:

import org.springframework.mail.MailSender;  
import org.springframework.mail.SimpleMailMessage;  

public class Account {  
   private String email;  
   private MailSender mailSender;  
   private boolean active = false;  

   public String getEmail() {  
      return email;  
   }  

   public void setEmail(String email) {  
      this.email = email;  
   }  

   public void setMailSender(MailSender mailSender) {  
      this.mailSender = mailSender;  
   }  

   public void activate() {  
      if (active) {  
      throw new IllegalStateException("Already active");  
      }  

      active = true;  
      sendActivationEmail();  
   }  

   private void sendActivationEmail() {  
      SimpleMailMessage msg = new SimpleMailMessage();  
      msg.setTo(email);  
      msg.setSubject("Congrats!");  
      msg.setText("You're the best.");  
      mailSender.send(msg);  
   }  
}

如果我使用 Hibernate,我可以使用DependencyInjectionInterceptorFactoryBeanin 来连接mailSender. 如果我改用 JDBC,我真的会编写以下繁琐的代码吗?另外,当我在 MVC 控制器中为 Account 创建一个新实例时,假设将其填充到模型中?

  BeanFactory beanFactory = new XmlBeanFactory(  
     new ClassPathResource("chapter3.xml"));  
  Account account = new Account();  
  account.setEmail("email@example.com");  
  ((AutowireCapableBeanFactory)beanFactory).applyBeanPropertyValues(  
        account, "accountPrototype");  
  account.activate(); 

这不可靠而且很麻烦,不是吗?每当我看到 Account 的实例时,我都会问自己该对象是在哪里创建的。另外,如果我采用这种方法:我没有一个可以通过的 appContext.xml,而是几个,一个用于持久性,一个用于服务配置。我该怎么做?另外,每次创建这样的实例时都会创建一个全新的上下文,或者我错过了什么?

没有更好的解决方案吗?

任何帮助是极大的赞赏。

4

1 回答 1

8

我认为发送激活电子邮件操作在这里不是业务层的一部分,您的域逻辑在这里是帐户激活操作,该逻辑应该存在于 DomainObjectwith name Account( activate()method ) 中。发送激活电子邮件infrastructure操作是层的一部分application

服务是处理账户激活请求和连接业务层等的对象。服务获取给定帐户,激活它们并执行MailSenderService或类似的发送激活电子邮件操作。

短样本:

public AccountServiceImpl implements AccountService
{
 private AccountDAO dao;
 private MailSenderService mailSender;

 public void activateAccount(AccountID accountID)
 {
   Account account = dao.findAccount(accountID);
   ....
   account.activate();
   dao.updateAccount(account);
   ....

   mailSender.sendActivationEmail(account);
 }

}

我可以建议的下一步是将业务层和基础设施层完全分离。这可以通过引入业务事件来获得。服务不再需要执行发送电子邮件的操作,它会创建事件通知其他层有关帐户激活的信息。

在 Spring 中,我们有两个处理事件的工具,ApplicationEventPublisher以及ApplicationListener.

简短的示例,发布域事件的服务:

public AccountActivationEvent extends ApplicationEvent {
    private Account account;

    AccountActivationEvent(Account account) {
       this.account = account;
    }

    public Account getActivatedAccount() {
       return account;
    }
}

public AccountServiceImpl implements AccountService, ApplicationEventPublisherAware
{
 private AccountDAO dao;
 private ApplicationEventPublisher epublisher;

 public void setApplicationEventPublisher(ApplicationEventPublisher epublisher) {
    this.epublisher = epublisher;
 }

 public void activateAccount(AccountID accountID)
 {
  Account account = dao.findAccount(accountID);
  ....
  account.activate();
  dao.updateAccount(account);
  ....

  epublisher.publishEvent(new AccountActivationEvent(account));
 }

}

和域事件监听器,在基础设施层:

public class SendAccountActivationEmailEventListener 
      implements ApplicationListener<AccountActivationEvent> {

  private MailSenderService mailSender;

  .... 

  public final void onApplicationEvent(final AccountActivationEvent event) {
   Account account = event.getActivatedAccount():
    .... perform mail ...
   mailSender.sendEmail(email);
  }
 }

现在您可以添加其他激活类型、日志记录、其他基础设施支持而无需更改并污染您的域(业务)层。

啊,你可以在文档中了解更多关于 spring 事件的信息

于 2012-07-30T10:39:03.807 回答