Spring的@Service逻辑与构建器模式(Builder Pattern)

huangapple go评论66阅读模式
英文:

Spring @Service logic with Builder Pattern

问题

我已经在Spring Boot应用程序中使用构建器模式实现了服务逻辑,代码如下:

@Service
public class EmailServiceImpl implements NotificationService{

    private Map<String, Object> emailTemplateContext;
    private List<String> recipients;
    private String templateName;
    private String subjectName;
    private List<String> ccRecipients;

    public EmailServiceImpl() {
    }

    private EmailServiceImpl(String templateName, String subjectName, List<String> recipients,
            List<String> ccRecipients,
            Map<String, Object> emailTemplateContext) {
        this.emailTemplateContext = emailTemplateContext;
        this.recipients = recipients;
        this.templateName = templateName;
        this.subjectName = subjectName;
        this.ccRecipients = ccRecipients;
    }
    
    public static class EmailBuilder {

        private Map<String, Object> emailTemplateContext = new HashMap<String, Object>();
        private List<String> recipients;
        private String templateName;
        private String subjectName;
        private List<String> ccRecipients;

        public EmailBuilder withTemplateName(String templateName) {
            this.templateName = templateName;
            return this;
        }

        public EmailBuilder withSubjectName(String subjectName) {
            this.subjectName = subjectName;
            return this;
        }

        public EmailBuilder withTemplateContextValues(String key, String value) {
            this.emailTemplateContext.put(key, value);
            return this;
        }
        
        public EmailBuilder withTemplateContextValues(String key, List<String> value) {
            this.emailTemplateContext.put(key, value);
            return this;
        }

        public EmailBuilder withRecipients(List<String> recipients) {
            this.recipients = recipients;
            return this;
        }

        public EmailBuilder withCCRecipients(List<String> ccRecipients) {
            this.ccRecipients = ccRecipients;
            return this;
        }

        public EmailServiceImpl build() {
            return new EmailServiceImpl(templateName, subjectName, recipients, ccRecipients, emailTemplateContext);
        }
    }
    
    public void send() {
     // 实现电子邮件发送逻辑
    }
}

然后,它将被注入到另一个类中,类似于以下方式:

public class EmailSender {
    private EmailBuilder emailBuilder;
    
    EmailSender(EmailBuilder emailBuilder) {
        this.emailBuilder = emailBuilder;
    }
    
    public void sendEmail() {
        this.emailBuilder
            .withRecipients(executionRunBO.getEmailRecipients().stream().map(email -> email.getEmail())
                    .collect(Collectors.toList()))
            .withSubjectName("Reports Draft ").withTemplateName("/emails/reports.ftlh")
            .withTemplateContextValues("userName", "TestUser").build().send();
    }
}

关于使用构建器模式和Spring的一些问题:

  1. 由于@Service注释的构造函数是私有的,Spring框架无法初始化该bean类。为了避免获得初始化异常,我将构造函数设置为了public,但这不是构建器模式的正确使用方式。如何正确地在Spring框架中实现构建器模式?

  2. 如何在服务类之外调用EmailServiceImpl类的EmailBuilder?在我的示例中,我已将EmailBuilder作为构造函数参数注入,然后Spring框架抛出以下错误:

    required a bean of type '...EmailServiceImpl$EmailBuilder' that could not be found.
    

请帮我澄清这些问题。

英文:

I have implemented service logic using builder pattern like below in a Spring boot application.

 @Service
public class EmailServiceImpl implements NotificationService{
private Map&lt;String, Object&gt; emailTemplateContext;;
private List&lt;String&gt; recipients;
private String templateName;
private String subjectName;
private List&lt;String&gt; ccRecipients;
public EmailServiceImpl() {
}
private EmailServiceImpl(String templateName, String subjectName, List&lt;String&gt; recipients,
List&lt;String&gt; ccRecipients,
Map&lt;String, Object&gt; emailTemplateContext) {
this.emailTemplateContext = emailTemplateContext;
this.recipients = recipients;
this.templateName = templateName;
this.subjectName = subjectName;
this.ccRecipients = ccRecipients;
}
public static class EmailBuilder {
private Map&lt;String, Object&gt; emailTemplateContext = new HashMap&lt;String, Object&gt;();
private List&lt;String&gt; recipients;
private String templateName;
private String subjectName;
private List&lt;String&gt; ccRecipients;
public EmailBuilder withTemplateName(String templateName) {
this.templateName = templateName;
return this;
}
public EmailBuilder withSubjectName(String subjectName) {
this.subjectName = subjectName;
return this;
}
public EmailBuilder withTemplateContextValues(String key, String value) {
this.emailTemplateContext.put(key, value);
return this;
}
public EmailBuilder withTemplateContextValues(String key,List&lt; String&gt; value) {
this.emailTemplateContext.put(key, value);
return this;
}
public EmailBuilder withRecipients(List&lt;String&gt; recipients) {
this.recipients = recipients;
return this;
}
public EmailBuilder withCCRecipients(List&lt;String&gt; ccRecipients) {
this.ccRecipients = ccRecipients;
return this;
}
public EmailServiceImpl build() {
return new EmailServiceImpl(templateName, subjectName, recipients, ccRecipients, emailTemplateContext);
}
}
public void send() {
// implement email send logic
}
}

Then this will be injected in another class something like below

 public class EmailSender{
private EmailBuilder emailBuilder;
EmailSender(EmailBuilder emailBuilder){
this.emailBuilder=emailBuilder;
}
public void sendEmail(){
this.emailBuilder
.withRecipients(executionRunBO.getEmailRecipients().stream().map(email -&gt; email.getEmail())
.collect(Collectors.toList()))
.withSubjectName(&quot;Reports Draft &quot;).withTemplateName(&quot;/emails/reports.ftlh&quot;)
.withTemplateContextValues(&quot;userName&quot;, &quot;TestUser&quot;).build().send();
}
}

There are few questions related to the Builder pattern with Spring.

  1. Since @service constructor is private Spring framework can not initiate the bean class.To avoid getting initialization exception i have made constructor to public but it is not the builder pattern.So how do i implement builder pattern correctly with Spring framework?

  2. How do i call the EmailServiceImpl class's EmailBuilder outside from the service class? Since in my examples i have injected EmailBuilder as a constructor argument then Spring framework throws that

> required a bean of type '...EmailServiceImpl$EmailBuilder' that could
> not be found.

Please help me to clarify those things.

答案1

得分: 1

你在这里将许多功能混在一起。我会让这个过程更加简化。

我会创建一个dto类Email,而不是一个Spring bean。

public class Email {
    private Map<String, Object> emailTemplateContext;
    private List<String> recipients;
    private String templateName;
    private String subjectName;
    private List<String> ccRecipients;

    private Email(String templateName, String subjectName, List<String> recipients,
                             List<String> ccRecipients,
                             Map<String, Object> emailTemplateContext) {
        this.emailTemplateContext = emailTemplateContext;
        this.recipients = recipients;
        this.templateName = templateName;
        this.subjectName = subjectName;
        this.ccRecipients = ccRecipients;
    }

    public static class EmailBuilder {
        // 你的构建器代码,只需构建Email
    }

}

然后创建一个用于发送电子邮件的服务。

@Service
public class EmailServiceImpl implements NotificationService {
    
    public void sendEmail(Email email) {
        
    }

}

像这样调用它

emailService.sendEmail(new Email.EmailBuilder().build());

没有必要为EmailEmailBuilder创建一个@service

英文:

You are mixing a lot of functionality together here. I would make this more streamlined.

I would create a dto class Email, not a Spring bean.

public class Email {
private Map&lt;String, Object&gt; emailTemplateContext;
private List&lt;String&gt; recipients;
private String templateName;
private String subjectName;
private List&lt;String&gt; ccRecipients;
private Email(String templateName, String subjectName, List&lt;String&gt; recipients,
List&lt;String&gt; ccRecipients,
Map&lt;String, Object&gt; emailTemplateContext) {
this.emailTemplateContext = emailTemplateContext;
this.recipients = recipients;
this.templateName = templateName;
this.subjectName = subjectName;
this.ccRecipients = ccRecipients;
}
public static class EmailBuilder {
// your builder code, just build the Email 
}
}

And then have a service to send emails.

@Service
public class EmailServiceImpl implements NotificationService {
public void sendEmail(Email email) {
}
}

Call it like this

emailService.sendEmail(new Email.EmailBuilder().build());

There is no need to create a @service from the Email and EmailBuilder.

huangapple
  • 本文由 发表于 2020年8月24日 16:50:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/63557676.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定