java 业务逻辑(以及那是什么?)应该在哪里真正存在,以及如何使用 Spring 做到这一点?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11690499/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Where should business logic (and what is that?) really live and how to do that with Spring?
提问by marc82ch
I was just reading this article:
我刚刚在读这篇文章:
http://www.tutorialized.com/view/tutorial/Spring-MVC-Application-Architecture/11986
http://www.tutorialized.com/view/tutorial/Spring-MVC-Application-Architecture/11986
which I find great. It explains the layer architecture nicely and I was glad that the architecture I'm working with pretty much is what he describes.
我觉得很棒。它很好地解释了层架构,我很高兴我正在使用的架构几乎就是他所描述的。
But there's one thing, that I don't seem to get:
但有一件事,我似乎没有得到:
First: what exactly is business logic and what is it not? In the article he says (and he's not the only one), that business logic should go in the domain model. So an Account
class should have an activate()
method that knows how to activate an Account
. In my understanding this would involve some persistence work probably. But the domain model should not have a dependency of DAOs. Only the service layer should know about DAOs.
第一:什么是业务逻辑,什么不是?在他的文章中(他不是唯一的),业务逻辑应该放在域模型中。所以一个Account
类应该有一个activate()
知道如何激活Account
. 据我了解,这可能涉及一些持久性工作。但是领域模型不应该依赖于 DAO。只有服务层应该知道 DAO。
So, is business logic just what a domain entity can do with itself? Like the activate()
method would set the active
property to true
, plus set the dateActivated
property to new Date()
and then it's the service's task to first call account.activate()
and second dao.saveAccount(account)
? And what needs external dependencies goes to a service? That's what I did until now mostly.
那么,业务逻辑是否只是域实体可以对自己做的事情?就像该activate()
方法将active
属性设置为true
,加上将dateActivated
属性设置为new 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)
{
...
}
}
This is in contrast to what he says, I think, no?
这与他所说的相反,我认为,不是吗?
What I also don't get is the example on how to have Spring wire domain objects like Account
. Which would be needed should Account send its e-mail on its own.
我也没有得到关于如何让 Spring 连线域对象(如Account
. 如果 Account 自己发送电子邮件,则需要哪些。
Given this code:
鉴于此代码:
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);
}
}
If I use Hibernate, I could use the DependencyInjectionInterceptorFactoryBean
in order to wire mailSender
. If I use JDBC instead, I'd really write the follwing cumbersome code? Plus, also when I create a new instance for Account in a MVC controller, for let's say populating it to a model??
如果我使用 Hibernate,我可以使用DependencyInjectionInterceptorFactoryBean
来连接mailSender
. 如果我改用JDBC,我真的会编写以下繁琐的代码吗?另外,当我在 MVC 控制器中为 Account 创建一个新实例时,假设将它填充到模型中?
BeanFactory beanFactory = new XmlBeanFactory(
new ClassPathResource("chapter3.xml"));
Account account = new Account();
account.setEmail("[email protected]");
((AutowireCapableBeanFactory)beanFactory).applyBeanPropertyValues(
account, "accountPrototype");
account.activate();
This is not reliable and very cumbersome, no? I'd have to ask myself where that object has been created, whenever I see an instance of Account. Plus, if I would go with this approach: I have not a single appContext.xml I could pass, but several, one for persistence, one for the service config. How would I do that? Plus, that would create a completely new context every time such an instance is created or am I missing something?
这不可靠而且很麻烦,不是吗?每当我看到 Account 的实例时,我都必须问自己该对象是在哪里创建的。另外,如果我采用这种方法:我没有一个可以传递的 appContext.xml,而是几个,一个用于持久性,一个用于服务配置。我该怎么做?另外,每次创建这样的实例时都会创建一个全新的上下文,还是我遗漏了什么?
Is there no better solution to that?
没有更好的解决办法吗?
Any help is greatly appreciated.
任何帮助是极大的赞赏。
采纳答案by masted
I think send activation emailaction is not a part of a business-layer here, your domain logic here is the account activationaction, that piece of logic should live in the DomainObject
with name Account
( activate()
method ). The send activation emailaction is the part of infrastructure
or application
layers.
我认为发送激活电子邮件操作不是这里业务层的一部分,这里的域逻辑是帐户激活操作,该逻辑应该存在于 DomainObject
名称Account
(activate()
方法)中。该发送激活邮件动作的部分infrastructure
或application
层。
Service is the object that handles account activation request and connects business-layer and others. Service takes the given account, activates them and performs send activation emailaction of MailSenderServiceor something like this.
服务是处理账户激活请求并连接业务层等的对象。Service 获取给定的帐户,激活它们并执行MailSenderService或类似的发送激活电子邮件操作。
Short sample:
短样本:
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);
}
}
The next step that I can suggest is a complete separation of business layer and a layer of infrastructure. This can be obtained by introducing the business event. Service no longer has to perform an action to send an email, it creates event notifying other layers about account activation.
我建议的下一步是完全分离业务层和基础设施层。这可以通过引入业务事件来获得。服务不再需要执行发送电子邮件的操作,它会创建事件通知其他层有关帐户激活的信息。
In the Spring we have two tools to work with events, ApplicationEventPublisher
and ApplicationListener
.
在 Spring 中,我们有两个工具来处理事件,ApplicationEventPublisher
以及ApplicationListener
.
Short example, service that publish domain events:
简短示例,发布域事件的服务:
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));
}
}
And domain event listener, on the infrastructure layer:
和领域事件监听器,在基础设施层:
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);
}
}
Now you can add another activation types, logging, other infrastructure stuff support without change and pollute your domain(business)-layer.
现在您可以添加另一种激活类型、日志记录、其他基础设施支持而无需更改并污染您的域(业务)层。
Ah, you can learn more about spring events in the documentation.