비동기 시리즈
0편:스프링 초기세팅하기 - https://dev-dx2d2y-log.tistory.com/102
1편:javax.mail로 메일보내기 - https://dev-dx2d2y-log.tistory.com/103
1.5편:내부클래스로 코드 간략화
2편:비동기처리로 클라이언트 풀어주기 - https://dev-dx2d2y-log.tistory.com/108

이펙티브자바에서 클래스를 호출하는 클래스가 단 하나일 경우 클래스를 그 클래스의 내부클래스로 옮기라고했다.
어제 개발한 메일보내기 시스템의 경우 실질적으로 메일을 보내는 MailSender 클래스는 오직 MailFilter에서만 접근가능하기 때문에 이에 해당하다고 판단, MailSender 클래스의 캡슐화를 위해 MailFilter 안쪽으로 중첩시켰다.
package com.ums.h2sm.Mail;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Service;
import javax.mail.*;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Properties;
@Service
class MailFilter {
void sendMailFilter(MailContentDTO mailContentDTO) throws MessagingException {
MailSender.sendMail(mailContentDTO);
}
private static class MailSender {
@Value("${spring.data.password}")
private String password;
private void sendMail(MailContentDTO contents)
throws MessagingException, AddressException {
System.out.println("시작");
long before = System.currentTimeMillis();
String user = "hongchelin422@gmail.com";
if (password == null) {
throw new NullPointerException();
}
String title = contents.getTitle();
String content = contents.getContent();
String address = contents.getEmailAddress();
Properties properties = new Properties();
properties.put("mail.smtp.host", "smtp.gmail.com");
properties.put("mail.smtp.port", "587");
properties.put("mail.smtp.auth", "true");
properties.put("mail.smtp.starttls.enable", "true");
Session session = Session.getInstance(properties, new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(user, password);
}
});
MimeMessage message = new MimeMessage(session);
try {
message.setFrom(new InternetAddress(user));
message.addRecipient(Message.RecipientType.TO, new InternetAddress((address)));
message.setSubject(title);
message.setText(content);
Transport.send(message);
long after = System.currentTimeMillis();
System.out.println("소요시간 : " + (-before + after));
} catch (MessagingException e) {
e.printStackTrace();
}
}
}
}
문제가 생겼는데, @Value 어노테이션은 static 필드에서는 적용되지 못한다. 그러면 외부에서 주입해주는 방법으로 사용해야한다. 그래서 static을 풀고 non-static으로 내부클래스를 정의했더니 내부클래스는 스프링 DI를 사용하지 못하고,
내부클래스에 @Service 어노테이션을 달아버리면 순환참조 오류가 터진다.
package com.ums.h2sm.Mail;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Service;
import javax.mail.*;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Properties;
@Service
class MailFilter {
@Value("${spring.data.password}")
private String password;
void sendMailFilter(MailContentDTO mailContentDTO) throws MessagingException {
MailSender.sendMail(password, mailContentDTO);
}
private static class MailSender {
private static void sendMail(String password, MailContentDTO contents)
throws MessagingException, AddressException {
System.out.println("시작");
long before = System.currentTimeMillis();
String user = "hongchelin422@gmail.com";
if (password == null) {
throw new NullPointerException();
}
String title = contents.getTitle();
String content = contents.getContent();
String address = contents.getEmailAddress();
Properties properties = new Properties();
properties.put("mail.smtp.host", "smtp.gmail.com");
properties.put("mail.smtp.port", "587");
properties.put("mail.smtp.auth", "true");
properties.put("mail.smtp.starttls.enable", "true");
Session session = Session.getInstance(properties, new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(user, password);
}
});
MimeMessage message = new MimeMessage(session);
try {
message.setFrom(new InternetAddress(user));
message.addRecipient(Message.RecipientType.TO, new InternetAddress((address)));
message.setSubject(title);
message.setText(content);
Transport.send(message);
long after = System.currentTimeMillis();
System.out.println("소요시간 : " + (-before + after));
} catch (MessagingException e) {
e.printStackTrace();
}
}
}
}
그래서 그냥 가변필드에서 받아서 매개변수로 전해주는 것으로 코드를 짰다.
개발할 때 SRP를 지킨다고 무조건 클래스 하나에 메서드 하나, 클래스 하나에 클래스 하나 (내부클래스 없이) 만을 고수했는데, 그게 깔끔할지는 몰라도 소스코드를 이리저리 왔다갔다해야해서 썩 보기좋지는 않았는다.
이렇게 하나로 합치니까 약간 길어보이고 복잡해보이긴해도 나름 깔끔하지 않나 생각된다. javadoc 같은걸로 주석 넣어주면 더 좋고
모든 소스코드는 깃허브에 올라가있다
깃허브도 정리해야되는데
'개인 프로젝트 > [2025] Happy2SendingMails' 카테고리의 다른 글
| [비동기-2편] 비동기처리로 클라이언트 풀어주기 (0) | 2025.10.25 |
|---|---|
| [비동기-1편] javax.mail로 메일보내기 (0) | 2025.10.21 |