[비동기-1.5편]내부클래스 사용해보기

2025. 10. 22. 13:37·개인 프로젝트/[2025] Happy2SendingMails
더보기

비동기 시리즈

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
'개인 프로젝트/[2025] Happy2SendingMails' 카테고리의 다른 글
  • [비동기-2편] 비동기처리로 클라이언트 풀어주기
  • [비동기-1편] javax.mail로 메일보내기
Radiata
Radiata
개발을 합니다.
  • Radiata
    DDD
    Radiata
  • 전체
    오늘
    어제
    • 분류 전체보기 (211)
      • 신년사 (3)
        • 2025년 (2)
        • 2026년 (1)
      • CS (59)
        • JVM (12)
        • 백엔드 (20)
        • 언어구현 (1)
        • 객체지향 (1)
        • 논리회로 (5)
        • 컴퓨터구조 (9)
        • 데이터베이스 (1)
        • 컴퓨터 네트워크 (10)
      • 언어공부 (64)
        • Java | Kotlin (48)
        • JavaScript | TypeScript (9)
        • C | C++ (6)
      • 개인 프로젝트 (11)
        • [2025] Happy2SendingMails (3)
        • [2026] 골든리포트! (8)
        • [2026] 순수자바로 개발하기 (0)
        • 기타 이것저것 (0)
      • 팀 프로젝트 (29)
        • [2025][GDG]홍대 맛집 아카이빙 프로젝트 (29)
      • 알고리즘 (13)
        • 백준풀이기록 (11)
      • 놀이터 (0)
      • 에러 수정일지 (2)
      • 고찰 (24)
        • CEOS 23기 회고록 (2)
  • 블로그 메뉴

    • CS
    • 언어공부
    • 개인 프로젝트
    • 팀 프로젝트
    • 알고리즘
    • 고찰
    • 신년사
    • 컬러잇 개발블로그
  • 링크

    • 컬러잇 개발블로그
  • 공지사항

  • 인기 글

  • 태그

    144
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
Radiata
[비동기-1.5편]내부클래스 사용해보기
상단으로

티스토리툴바