์ ์ธ๊ณ ๊ฐ๋ฐ์๋ฅผ ์ํด ์คํ๋ง ๊ฐ๋ฐ์ ํต์ฌ ๊ฐ๋ , ๋ชจ๋ฒ ์ฌ๋ก, ๊ณ ๊ธ ๊ธฐ์ ๋ฐ ์ต์ ๋ํฅ์ ๋ค๋ฃจ๋ ์ข ํฉ ๊ฐ์ด๋์ ๋๋ค.
์คํ๋ง ๊ฐ๋ฐ ๋ง์คํฐํ๊ธฐ: ์ ์ธ๊ณ ๊ฐ๋ฐ์๋ฅผ ์ํ ์ข ํฉ ๊ฐ์ด๋
์คํ๋ง ํ๋ ์์ํฌ๋ ์ํฐํ๋ผ์ด์ฆ ์๋ฐ ๊ฐ๋ฐ์ ์ด์์ด ๋์ด, ์ ์ธ๊ณ ๊ฐ๋ฐ์๋ค์ด ๊ฒฌ๊ณ ํ๊ณ ํ์ฅ ๊ฐ๋ฅํ๋ฉฐ ์ ์ง๋ณด์ํ๊ธฐ ์ฌ์ด ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ ์ ์๋๋ก ์ง์ํฉ๋๋ค. ์ด ์ข ํฉ ๊ฐ์ด๋๋ ์คํ๋ง ๊ฐ๋ฐ์ ๋ํ ์ฌ์ธต์ ์ธ ๋ด์ฉ์ ์ ๊ณตํ๋ฉฐ, ์ด ๊ฐ๋ ฅํ ํ๋ ์์ํฌ๋ฅผ ๋ง์คํฐํ๋ ๋ฐ ๋์์ด ๋๋ ํ์ ๊ฐ๋ , ๋ชจ๋ฒ ์ฌ๋ก ๋ฐ ๊ณ ๊ธ ๊ธฐ์ ์ ๋ค๋ฃน๋๋ค.
์คํ๋ง ํ๋ ์์ํฌ๋ ๋ฌด์์ธ๊ฐ?
์คํ๋ง ํ๋ ์์ํฌ๋ ์๋ฐ ํ๋ซํผ์ ์ํ ์คํ์์ค ์ ํ๋ฆฌ์ผ์ด์ ํ๋ ์์ํฌ์ด์ ์ ์ด์ ์ญ์ (IoC) ์ปจํ ์ด๋์ ๋๋ค. ๊ฐ๋จํ ์น ์ ํ๋ฆฌ์ผ์ด์ ๋ถํฐ ๋ณต์กํ ์ํฐํ๋ผ์ด์ฆ ์๋ฃจ์ ์ ์ด๋ฅด๊ธฐ๊น์ง ์๋ฐ ์ ํ๋ฆฌ์ผ์ด์ ๊ฐ๋ฐ์ ์ํ ํฌ๊ด์ ์ธ ์ธํ๋ผ ์ง์์ ์ ๊ณตํฉ๋๋ค. ๋ชจ๋์ ์ค๊ณ๋ฅผ ํตํด ๊ฐ๋ฐ์๋ ํ์ํ ํ๋ ์์ํฌ ๋ถ๋ถ๋ง ์ฌ์ฉํ ์ ์์ด ๋ค์ํ ํ๋ก์ ํธ ์๊ตฌ์ฌํญ์ ๋งค์ฐ ์ ์ฐํ๊ฒ ์ ์ํ ์ ์์ต๋๋ค.
์คํ๋ง ํ๋ ์์ํฌ์ ์ฃผ์ ํน์ง
- ์์กด์ฑ ์ฃผ์ (DI): ์คํ๋ง์ ํต์ฌ ์์น์ธ DI๋ ์ ํ๋ฆฌ์ผ์ด์ ๊ตฌ์ฑ ์์ ๊ฐ์ ์์กด์ฑ์ ๋์จํ๊ฒ ๊ฒฐํฉ๋ ๋ฐฉ์์ผ๋ก ๊ด๋ฆฌํ์ฌ ํ ์คํธ ์ฉ์ด์ฑ๊ณผ ์ ์ง๋ณด์์ฑ์ ํฅ์์ํต๋๋ค. ์๋ฅผ ๋ค์ด, ํด๋์ค ๋ด์์ ์ง์ ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ ๋์ , ์ธ๋ถ ์์ค(์คํ๋ง ์ปจํ ์ด๋)๋ก๋ถํฐ ๊ฐ์ฒด๊ฐ ํด๋์ค์ ์ ๊ณต๋ฉ๋๋ค.
- ๊ด์ ์งํฅ ํ๋ก๊ทธ๋๋ฐ(AOP): AOP๋ฅผ ์ฌ์ฉํ๋ฉด ๋ก๊น , ๋ณด์, ํธ๋์ญ์ ๊ด๋ฆฌ์ ๊ฐ์ ํก๋จ ๊ด์ฌ์ฌ๋ฅผ ๋ณ๋์ ์ ์คํํธ(aspect)๋ก ๋ชจ๋ํํ ์ ์์ต๋๋ค. ์ด๋ ์ฝ๋์ ๋ช ํ์ฑ์ ํฅ์์ํค๊ณ ์ฝ๋ ์ค๋ณต์ ์ค์ ๋๋ค.
- ๋ฐ์ดํฐ ์ ๊ทผ ์ถ์ํ: ์คํ๋ง์ ๊ด๊ณํ ๋ฐ์ดํฐ๋ฒ ์ด์ค, NoSQL ๋ฐ์ดํฐ๋ฒ ์ด์ค, ๋ฉ์์ง ํ ๋ฑ ๋ค์ํ ๋ฐ์ดํฐ ์์ค๋ฅผ ์ง์ํ๋ฉฐ, ์ผ๊ด๋๊ณ ๋จ์ํ๋ ๋ฐ์ดํฐ ์ ๊ทผ ๋ฐฉ์์ ์ ๊ณตํฉ๋๋ค. ์คํ๋ง ๋ฐ์ดํฐ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ํธ ์์ฉ๊ณผ ๊ด๋ จ๋ ๋ง์ ์์ฉ๊ตฌ ์ฝ๋๋ฅผ ์ถ์ํํฉ๋๋ค.
- ํธ๋์ญ์ ๊ด๋ฆฌ: ์คํ๋ง์ ์ฌ๋ฌ ๋ค๋ฅธ ๋ฐ์ดํฐ ์์ค์ ๊ฑธ์ณ ํธ๋์ญ์ ์ ๊ด๋ฆฌํ๋ ๊ณผ์ ์ ๋จ์ํํ๋ ์ ์ธ์ ํธ๋์ญ์ ๊ด๋ฆฌ ์์คํ ์ ์ ๊ณตํฉ๋๋ค. ์ด๋ ๋ฐ์ดํฐ์ ์ผ๊ด์ฑ๊ณผ ๋ฌด๊ฒฐ์ฑ์ ๋ณด์ฅํ๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค.
- ์น ๊ฐ๋ฐ: ์คํ๋ง MVC(Model-View-Controller)๋ ์น ์ ํ๋ฆฌ์ผ์ด์ ๊ณผ REST API๋ฅผ ๊ตฌ์ถํ๊ธฐ ์ํ ๊ฐ๋ ฅํ๊ณ ์ ์ฐํ ํ๋ ์์ํฌ๋ฅผ ์ ๊ณตํฉ๋๋ค. ๋ค์ด์ค๋ ์์ฒญ์ ์ฒ๋ฆฌํ๊ณ ์ ์ ํ ์๋ต์ ๋ฐํํ๋ ์ปจํธ๋กค๋ฌ๋ฅผ ์ฝ๊ฒ ๋ง๋ค ์ ์์ต๋๋ค.
- ํ ์คํธ ์ง์: ์คํ๋ง์ ๋จ์ ๋ฐ ํตํฉ ํ ์คํธ๋ฅผ ์ํ ๋ฐ์ด๋ ์ง์์ ์ ๊ณตํ์ฌ ๊ณ ํ์ง์ ์ ๋ขฐํ ์ ์๋ ์ฝ๋๋ฅผ ๋ ์ฝ๊ฒ ์์ฑํ ์ ์๋๋ก ํฉ๋๋ค.
- ์คํ๋ง ๋ถํธ: ์๋ ๊ตฌ์ฑ ๋ฐ ๋ด์ฅ ์๋ฒ๋ฅผ ํตํด ์คํ๋ง ์ ํ๋ฆฌ์ผ์ด์ ์ ์ค์ ๊ณผ ๊ตฌ์ฑ์ ๋จ์ํํฉ๋๋ค.
์คํ๋ง ๋ถํธ๋ก ์์ํ๊ธฐ
์คํ๋ง ๋ถํธ๋ ์คํ๋ง ๊ธฐ๋ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ง๋๋ ๊ณผ์ ์ ํ๊ธฐ์ ์ผ๋ก ๋จ์ํํฉ๋๋ค. ์๋ ๊ตฌ์ฑ, ๋ด์ฅ ์๋ฒ ๋ฐ ํ์ํ ์์ฉ๊ตฌ ์ฝ๋์ ์์ ์ค์ฌ์ฃผ๋ ๋ค์ํ ๊ธฐํ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
์คํ๋ง ๋ถํธ ํ๋ก์ ํธ ์ค์ ํ๊ธฐ
์คํ๋ง ๋ถํธ๋ฅผ ์์ํ๋ ๊ฐ์ฅ ์ฌ์ด ๋ฐฉ๋ฒ์ Spring Initializr(start.spring.io)๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๋๋ค. ์ด ์น ๊ธฐ๋ฐ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ๋ฉด ํ์ํ ์์กด์ฑ์ ๊ฐ์ถ ๊ธฐ๋ณธ ์คํ๋ง ๋ถํธ ํ๋ก์ ํธ๋ฅผ ์์ฑํ ์ ์์ต๋๋ค. ์ ํธํ๋ ๋น๋ ๋๊ตฌ(Maven ๋๋ Gradle), ์๋ฐ ๋ฒ์ ๋ฐ ์์กด์ฑ์ ์ ํํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, "Web", "JPA", "H2"๋ฅผ ์ ํํ์ฌ ๊ด๊ณํ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ฌ์ฉํ๋ ๊ฐ๋จํ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ง๋ค ์ ์์ต๋๋ค.
์์ : ์คํ๋ง ๋ถํธ๋ก ๊ฐ๋จํ REST API ๋ง๋ค๊ธฐ
"Hello, World!" ๋ฉ์์ง๋ฅผ ๋ฐํํ๋ ๊ฐ๋จํ REST API๋ฅผ ๋ง๋ค์ด ๋ณด๊ฒ ์ต๋๋ค.
1. Spring Initializr๋ฅผ ์ฌ์ฉํ์ฌ ์คํ๋ง ๋ถํธ ํ๋ก์ ํธ๋ฅผ ์์ฑํฉ๋๋ค.
2. ํ๋ก์ ํธ์ `spring-boot-starter-web` ์์กด์ฑ์ ์ถ๊ฐํฉ๋๋ค.
3. ์ปจํธ๋กค๋ฌ ํด๋์ค๋ฅผ ์์ฑํฉ๋๋ค:
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "Hello, World!";
}
}
4. ์ ํ๋ฆฌ์ผ์ด์ ์ ์คํํฉ๋๋ค.
์ด์ `http://localhost:8080/hello`์์ API ์๋ํฌ์ธํธ์ ์ ์ํ๋ฉด "Hello, World!" ๋ฉ์์ง๋ฅผ ๋ณผ ์ ์์ต๋๋ค.
์คํ๋ง ๊ฐ๋ฐ์ ํต์ฌ ๊ฐ๋
์์กด์ฑ ์ฃผ์ (DI)๊ณผ ์ ์ด์ ์ญ์ (IoC)
์์กด์ฑ ์ฃผ์ (DI)์ ์ ํ๋ฆฌ์ผ์ด์ ๊ตฌ์ฑ ์์ ๊ฐ์ ๋์จํ ๊ฒฐํฉ์ ์ด์งํ๋ ๋์์ธ ํจํด์ ๋๋ค. ๊ฐ์ฒด๊ฐ ์์ ์ ์์กด์ฑ์ ์ง์ ์์ฑํ๋ ๋์ , ์์กด์ฑ์ด ๊ฐ์ฒด์ ์ฃผ์ ๋ฉ๋๋ค. ์ ์ด์ ์ญ์ (IoC)์ ํ๋ ์์ํฌ(์คํ๋ง ์ปจํ ์ด๋)๊ฐ ๊ฐ์ฒด์ ์์ฑ๊ณผ ์ฐ๊ฒฐ์ ๊ด๋ฆฌํ๋ ๋ฐฉ์์ ์ค๋ช ํ๋ ๋ ๋์ ์์น์ ๋๋ค.
DI์ IoC์ ์ด์
- ํฅ์๋ ํ ์คํธ ์ฉ์ด์ฑ: ํ ์คํธ ๋ชฉ์ ์ผ๋ก ์์กด์ฑ์ ์ฝ๊ฒ ๋ชจ์(mock)ํ๊ฑฐ๋ ์คํ (stub)์ผ๋ก ๋ง๋ค ์ ์์ต๋๋ค.
- ์ฆ๊ฐ๋ ์ฌ์ฌ์ฉ์ฑ: ๊ตฌ์ฑ ์์๋ค์ด ๋ ๊ธด๋ฐํ๊ฒ ๊ฒฐํฉ๋์ด ์์ด ๋ค๋ฅธ ์ปจํ ์คํธ์์ ์ฌ์ฌ์ฉํ๊ธฐ๊ฐ ๋ ์ฝ์ต๋๋ค.
- ํฅ์๋ ์ ์ง๋ณด์์ฑ: ํ ๊ตฌ์ฑ ์์์ ๋ณ๊ฒฝ์ด ๋ค๋ฅธ ๊ตฌ์ฑ ์์์ ์ํฅ์ ๋ฏธ์น ๊ฐ๋ฅ์ฑ์ด ์ ์ต๋๋ค.
์์ : ์คํ๋ง์์ DI ์ฌ์ฉํ๊ธฐ
@Service
public class UserService {
private final UserRepository userRepository;
@Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public User getUserById(Long id) {
return userRepository.findById(id).orElse(null);
}
}
@Repository
public interface UserRepository extends JpaRepository {
}
์ด ์์ ์์ `UserService`๋ `UserRepository`์ ์์กดํฉ๋๋ค. `UserRepository`๋ `@Autowired` ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ์ฌ `UserService`์ ์์ฑ์์ ์ฃผ์ ๋ฉ๋๋ค. ์ด๋ฅผ ํตํด ์คํ๋ง์ด ์ด๋ฌํ ๊ตฌ์ฑ ์์์ ์์ฑ๊ณผ ์ฐ๊ฒฐ์ ๊ด๋ฆฌํ ์ ์์ต๋๋ค.
๊ด์ ์งํฅ ํ๋ก๊ทธ๋๋ฐ(AOP)
๊ด์ ์งํฅ ํ๋ก๊ทธ๋๋ฐ(AOP)์ ๋ก๊น , ๋ณด์, ํธ๋์ญ์ ๊ด๋ฆฌ์ ๊ฐ์ ํก๋จ ๊ด์ฌ์ฌ๋ฅผ ๋ชจ๋ํํ ์ ์๊ฒ ํด์ฃผ๋ ํ๋ก๊ทธ๋๋ฐ ํจ๋ฌ๋ค์์ ๋๋ค. ์ ์คํํธ(aspect)๋ ์ด๋ฌํ ํก๋จ ๊ด์ฌ์ฌ๋ฅผ ์บก์ํํ๋ ๋ชจ๋์ ๋๋ค.
AOP์ ์ด์
- ์ฝ๋ ์ค๋ณต ๊ฐ์: ํก๋จ ๊ด์ฌ์ฌ๊ฐ ํ ๊ณณ์์ ๊ตฌํ๋์ด ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฌ๋ฌ ๋ถ๋ถ์ ์ ์ฉ๋ฉ๋๋ค.
- ์ฝ๋ ๋ช ํ์ฑ ํฅ์: ํต์ฌ ๋น์ฆ๋์ค ๋ก์ง์ด ํก๋จ ๊ด์ฌ์ฌ์ ๋ถ๋ฆฌ๋์ด ์ฝ๋๋ฅผ ์ดํดํ๊ธฐ๊ฐ ๋ ์ฌ์์ง๋๋ค.
- ํฅ์๋ ์ ์ง๋ณด์์ฑ: ํก๋จ ๊ด์ฌ์ฌ์ ๋ํ ๋ณ๊ฒฝ์ ํต์ฌ ๋น์ฆ๋์ค ๋ก์ง์ ์ํฅ์ ์ฃผ์ง ์๊ณ ํ ๊ณณ์์ ์ํํ ์ ์์ต๋๋ค.
์์ : ๋ก๊น ์ ์ํ AOP ์ฌ์ฉํ๊ธฐ
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LoggingAspect {
private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);
@Before("execution(* com.example.service.*.*(..))")
public void logBefore(JoinPoint joinPoint) {
logger.info("Method " + joinPoint.getSignature().getName() + " called");
}
}
์ด ์์ ๋ `com.example.service` ํจํค์ง์ ๋ชจ๋ ๋ฉ์๋ ์คํ ์ ์ ๋ฉ์์ง๋ฅผ ๊ธฐ๋กํ๋ ์ ์คํํธ๋ฅผ ์ ์ํฉ๋๋ค. `@Before` ์ด๋ ธํ ์ด์ ์ ์ด๋๋ฐ์ด์ค(๋ก๊น ๋ก์ง)๊ฐ ์คํ๋์ด์ผ ํ ์์ ์ ๊ฒฐ์ ํ๋ ํฌ์ธํธ์ปท(pointcut)์ ์ง์ ํฉ๋๋ค.
์คํ๋ง ๋ฐ์ดํฐ
์คํ๋ง ๋ฐ์ดํฐ๋ ๊ด๊ณํ ๋ฐ์ดํฐ๋ฒ ์ด์ค, NoSQL ๋ฐ์ดํฐ๋ฒ ์ด์ค, ๋ฉ์์ง ํ ๋ฑ ๋ค์ํ ๋ฐ์ดํฐ ์์ค๋ฅผ ์ง์ํ๋ฉฐ, ์ผ๊ด๋๊ณ ๋จ์ํ๋ ๋ฐ์ดํฐ ์ ๊ทผ ๋ฐฉ์์ ์ ๊ณตํฉ๋๋ค. ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ํธ ์์ฉ๊ณผ ๊ด๋ จ๋ ๋ง์ ์์ฉ๊ตฌ ์ฝ๋๋ฅผ ์ถ์ํํ์ฌ ๊ฐ๋ฐ์๊ฐ ๋น์ฆ๋์ค ๋ก์ง์ ์ง์คํ ์ ์๋๋ก ํฉ๋๋ค.
์คํ๋ง ๋ฐ์ดํฐ์ ์ฃผ์ ๋ชจ๋
- ์คํ๋ง ๋ฐ์ดํฐ JPA: ์๋ฐ ํผ์์คํด์ค API(JPA)๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ ์ ๊ทผ์ ํ๋ ์ ํ๋ฆฌ์ผ์ด์ ๊ฐ๋ฐ์ ๋จ์ํํฉ๋๋ค.
- ์คํ๋ง ๋ฐ์ดํฐ MongoDB: NoSQL ๋ฌธ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ธ MongoDB์์ ํตํฉ์ ์ ๊ณตํฉ๋๋ค.
- ์คํ๋ง ๋ฐ์ดํฐ Redis: ๋ฐ์ดํฐ๋ฒ ์ด์ค, ์บ์, ๋ฉ์์ง ๋ธ๋ก์ปค๋ก ์ฌ์ฉ๋๋ ์ธ๋ฉ๋ชจ๋ฆฌ ๋ฐ์ดํฐ ๊ตฌ์กฐ ์ ์ฅ์์ธ Redis๋ฅผ ์ง์ํฉ๋๋ค.
- ์คํ๋ง ๋ฐ์ดํฐ Cassandra: NoSQL ์์ด๋ ์ปฌ๋ผ ์คํ ์ด ๋ฐ์ดํฐ๋ฒ ์ด์ค์ธ Apache Cassandra์ ํตํฉ๋ฉ๋๋ค.
์์ : ์คํ๋ง ๋ฐ์ดํฐ JPA ์ฌ์ฉํ๊ธฐ
@Repository
public interface ProductRepository extends JpaRepository {
List findByNameContaining(String name);
}
์ด ์์ ๋ ์คํ๋ง ๋ฐ์ดํฐ JPA๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ๋จํ ๋ฆฌํฌ์งํ ๋ฆฌ ์ธํฐํ์ด์ค๋ฅผ ๋ง๋๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค. `JpaRepository` ์ธํฐํ์ด์ค๋ ์ผ๋ฐ์ ์ธ CRUD(์์ฑ, ์ฝ๊ธฐ, ์์ , ์ญ์ ) ์์ ์ ์ ๊ณตํฉ๋๋ค. ๋ํ ๋ช ๋ช ๊ท์น์ ๋ฐ๋ฅด๊ฑฐ๋ `@Query` ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ์ฌ ์ฌ์ฉ์ ์ ์ ์ฟผ๋ฆฌ ๋ฉ์๋๋ฅผ ์ ์ํ ์ ์์ต๋๋ค.
์คํ๋ง ์ํ๋ฆฌํฐ
์คํ๋ง ์ํ๋ฆฌํฐ๋ ์๋ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ํ ๊ฐ๋ ฅํ๊ณ ๊ณ ๋๋ก ์ฌ์ฉ์ ์ ์ ๊ฐ๋ฅํ ์ธ์ฆ ๋ฐ ๊ถํ ๋ถ์ฌ ํ๋ ์์ํฌ์ ๋๋ค. ์ธ์ฆ, ๊ถํ ๋ถ์ฌ, ์ผ๋ฐ์ ์ธ ์น ๊ณต๊ฒฉ ๋ฐฉ์ด ๋ฑ ํฌ๊ด์ ์ธ ๋ณด์ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
์คํ๋ง ์ํ๋ฆฌํฐ์ ์ฃผ์ ํน์ง
- ์ธ์ฆ: ์ฌ์ฉ์์ ์ ์์ ํ์ธํฉ๋๋ค.
- ๊ถํ ๋ถ์ฌ: ์ฌ์ฉ์๊ฐ ์ ๊ทผํ ์ ์๋ ๋ฆฌ์์ค๋ฅผ ๊ฒฐ์ ํฉ๋๋ค.
- ์ผ๋ฐ์ ์ธ ์น ๊ณต๊ฒฉ ๋ฐฉ์ด: ์คํ๋ง ์ํ๋ฆฌํฐ๋ ๊ต์ฐจ ์ฌ์ดํธ ์คํฌ๋ฆฝํ (XSS), ๊ต์ฐจ ์ฌ์ดํธ ์์ฒญ ์์กฐ(CSRF), SQL ์ธ์ ์ ๊ณผ ๊ฐ์ ์ผ๋ฐ์ ์ธ ์น ๊ณต๊ฒฉ์ ๋ํ ๋ด์ฅ ๋ณดํธ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
์์ : ์คํ๋ง ์ํ๋ฆฌํฐ๋ก REST API ๋ณดํธํ๊ธฐ
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/public/**").permitAll()
.anyRequest().authenticated()
.and()
.httpBasic();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("{noop}password").roles("USER");
}
}
์ด ์์ ๋ `/public/**` ์๋ํฌ์ธํธ๋ฅผ ์ ์ธํ ๋ชจ๋ ์์ฒญ์ ๋ํด ์ธ์ฆ์ ์๊ตฌํ๋๋ก ์คํ๋ง ์ํ๋ฆฌํฐ๋ฅผ ๊ตฌ์ฑํฉ๋๋ค. ๋ํ ์ฌ์ฉ์ ์ด๋ฆ์ด "user"์ด๊ณ ๋น๋ฐ๋ฒํธ๊ฐ "password"์ธ ์ธ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ์๋ฅผ ์ ์ํฉ๋๋ค.
๊ณ ๊ธ ์คํ๋ง ๊ฐ๋ฐ ๊ธฐ์
์คํ๋ง ํด๋ผ์ฐ๋๋ฅผ ์ด์ฉํ ๋ง์ดํฌ๋ก์๋น์ค ์ํคํ ์ฒ
๋ง์ดํฌ๋ก์๋น์ค ์ํคํ ์ฒ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋น์ฆ๋์ค ๋๋ฉ์ธ์ ์ค์ฌ์ผ๋ก ๋ชจ๋ธ๋ง๋ ์๊ณ ์์จ์ ์ธ ์๋น์ค์ ๋ชจ์์ผ๋ก ๊ตฌ์กฐํํ๋ ์ํํธ์จ์ด ๊ฐ๋ฐ ์ ๊ทผ ๋ฐฉ์์ ๋๋ค. ์คํ๋ง ํด๋ผ์ฐ๋๋ ์คํ๋ง ๋ถํธ๋ก ๋ง์ดํฌ๋ก์๋น์ค ๊ธฐ๋ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ๊ธฐ ์ํ ๋๊ตฌ ๋ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ธํธ๋ฅผ ์ ๊ณตํฉ๋๋ค.
์คํ๋ง ํด๋ผ์ฐ๋์ ์ฃผ์ ๊ตฌ์ฑ ์์
- ์๋น์ค ๋์ค์ปค๋ฒ๋ฆฌ (Eureka, Consul): ์๋น์ค๊ฐ ๋์ ์ผ๋ก ์๋ก๋ฅผ ๋ฐ๊ฒฌํ๊ณ ํต์ ํ ์ ์๋๋ก ํฉ๋๋ค.
- API ๊ฒ์ดํธ์จ์ด (Zuul, Spring Cloud Gateway): ํด๋ผ์ด์ธํธ๊ฐ ๋ง์ดํฌ๋ก์๋น์ค์ ์ ๊ทผํ ์ ์๋ ๋จ์ผ ์ง์ ์ ์ ์ ๊ณตํฉ๋๋ค.
- ๊ตฌ์ฑ ๊ด๋ฆฌ (Spring Cloud Config): ๋ง์ดํฌ๋ก์๋น์ค์ ๊ตฌ์ฑ์ ์ค์์์ ๊ด๋ฆฌํฉ๋๋ค.
- ์ํท ๋ธ๋ ์ด์ปค (Hystrix, Resilience4j): ๋ถ์ฐ ์์คํ ์์ ์ฐ์์ ์ธ ์ฅ์ ๋ก๋ถํฐ ๋ณดํธํฉ๋๋ค.
- ๋ฉ์์ง ๋ธ๋ก์ปค (RabbitMQ, Kafka): ๋ง์ดํฌ๋ก์๋น์ค ๊ฐ์ ๋น๋๊ธฐ ํต์ ์ ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค.
์คํ๋ง ์นํ๋ญ์ค๋ฅผ ์ด์ฉํ ๋ฐ์ํ ํ๋ก๊ทธ๋๋ฐ
๋ฐ์ํ ํ๋ก๊ทธ๋๋ฐ์ ๋น๋๊ธฐ ๋ฐ์ดํฐ ์คํธ๋ฆผ๊ณผ ๋ณํ์ ์ ํ๋ฅผ ๋ค๋ฃจ๋ ํ๋ก๊ทธ๋๋ฐ ํจ๋ฌ๋ค์์ ๋๋ค. ์คํ๋ง ์นํ๋ญ์ค๋ ์๋ฐ์ฉ ๋ฐ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ธ ๋ฆฌ์กํฐ(Reactor) ์์ ๊ตฌ์ถ๋ ๋ฐ์ํ ์น ํ๋ ์์ํฌ์ ๋๋ค.
๋ฐ์ํ ํ๋ก๊ทธ๋๋ฐ์ ์ด์
- ์ฑ๋ฅ ํฅ์: ๋ฐ์ํ ํ๋ก๊ทธ๋๋ฐ์ ์์ฒญ์ ๋น๋๊ธฐ ๋ฐ ๋ ผ๋ธ๋กํน ๋ฐฉ์์ผ๋ก ์ฒ๋ฆฌํ์ฌ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฑ๋ฅ์ ํฅ์์ํฌ ์ ์์ต๋๋ค.
- ํ์ฅ์ฑ ์ฆ๊ฐ: ๋ฐ์ํ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ต์ํ์ ๋ฆฌ์์ค ์๋น๋ก ๋ง์ ์์ ๋์ ์์ฒญ์ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
- ์๋ต์ฑ ํฅ์: ๋ฐ์ํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฐ์ดํฐ ์คํธ๋ฆผ์ ์ค์๊ฐ์ผ๋ก ์ฒ๋ฆฌํ์ฌ ๋ ๋์ ์ฌ์ฉ์ ๊ฒฝํ์ ์ ๊ณตํ ์ ์์ต๋๋ค.
์คํ๋ง ์ ํ๋ฆฌ์ผ์ด์ ํ ์คํธ
ํ ์คํธ๋ ์ํํธ์จ์ด ๊ฐ๋ฐ ๊ณผ์ ์ ํ์์ ์ธ ๋ถ๋ถ์ ๋๋ค. ์คํ๋ง์ ๋จ์ ๋ฐ ํตํฉ ํ ์คํธ๋ฅผ ์ํ ๋ฐ์ด๋ ์ง์์ ์ ๊ณตํฉ๋๋ค.
ํ ์คํธ์ ์ข ๋ฅ
- ๋จ์ ํ ์คํธ: ๊ฐ๋ณ ๊ตฌ์ฑ ์์๋ฅผ ๊ฒฉ๋ฆฌํ์ฌ ํ ์คํธํฉ๋๋ค.
- ํตํฉ ํ ์คํธ: ์๋ก ๋ค๋ฅธ ๊ตฌ์ฑ ์์ ๋๋ ์์คํ ๊ฐ์ ์ํธ ์์ฉ์ ํ ์คํธํฉ๋๋ค.
- ์๋ ํฌ ์๋ ํ ์คํธ: ์ฌ์ฉ์์ ๊ด์ ์์ ์ ์ฒด ์ ํ๋ฆฌ์ผ์ด์ ์ ํ ์คํธํฉ๋๋ค.
์คํ๋ง ์ ํ๋ฆฌ์ผ์ด์ ํ ์คํธ ๋๊ตฌ
- JUnit: ์๋ฐ๋ฅผ ์ํ ์ธ๊ธฐ ์๋ ๋จ์ ํ ์คํธ ํ๋ ์์ํฌ์ ๋๋ค.
- Mockito: ์๋ฐ๋ฅผ ์ํ ๋ชจ์(mocking) ํ๋ ์์ํฌ์ ๋๋ค.
- Spring Test: ์คํ๋ง ์ ํ๋ฆฌ์ผ์ด์ ํ ์คํธ๋ฅผ ์ํ ์ ํธ๋ฆฌํฐ๋ฅผ ์ ๊ณตํฉ๋๋ค.
- Selenium: ์๋ ํฌ ์๋ ํ ์คํธ๋ฅผ ์ํ ๋ธ๋ผ์ฐ์ ์๋ํ ๋๊ตฌ์ ๋๋ค.
์คํ๋ง ๊ฐ๋ฐ ๋ชจ๋ฒ ์ฌ๋ก
- SOLID ์์น ๋ฐ๋ฅด๊ธฐ: ์ฝ๋์ ์ ์ง๋ณด์์ฑ๊ณผ ์ฌ์ฌ์ฉ์ฑ์ ํฅ์์ํค๊ธฐ ์ํด SOLID ์์น์ ๋ฐ๋ผ ํด๋์ค๋ฅผ ์ค๊ณํ์ญ์์ค.
- ์์กด์ฑ ์ฃผ์ ์ฌ์ฉํ๊ธฐ: ์์กด์ฑ ์ฃผ์ ์ ํ์ฉํ์ฌ ๊ตฌ์ฑ ์์์ ๊ฒฐํฉ๋๋ฅผ ๋ฎ์ถ๊ณ ํ ์คํธ ์ฉ์ด์ฑ์ ํฅ์์ํค์ญ์์ค.
- ๋จ์ ํ ์คํธ ์์ฑํ๊ธฐ: ๋ชจ๋ ๊ตฌ์ฑ ์์๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์๋ํ๋์ง ํ์ธํ๊ธฐ ์ํด ๋จ์ ํ ์คํธ๋ฅผ ์์ฑํ์ญ์์ค.
- ์ผ๊ด๋ ์ฝ๋ฉ ์คํ์ผ ์ฌ์ฉํ๊ธฐ: ์ฝ๋ ๊ฐ๋ ์ฑ๊ณผ ์ ์ง๋ณด์์ฑ์ ํฅ์์ํค๊ธฐ ์ํด ์ผ๊ด๋ ์ฝ๋ฉ ์คํ์ผ์ ๋ฐ๋ฅด์ญ์์ค. Checkstyle์ด๋ SonarQube์ ๊ฐ์ ๋๊ตฌ๊ฐ ์ฝ๋ฉ ํ์ค์ ๊ฐ์ ํ๋ ๋ฐ ๋์์ด ๋ ์ ์์ต๋๋ค.
- ์์ธ๋ฅผ ์ฌ๋ฐ๋ฅด๊ฒ ์ฒ๋ฆฌํ๊ธฐ: ์ ํ๋ฆฌ์ผ์ด์ ์ถฉ๋์ ๋ฐฉ์งํ๊ธฐ ์ํด ๊ฒฌ๊ณ ํ ์์ธ ์ฒ๋ฆฌ ์ ๋ต์ ๊ตฌํํ์ญ์์ค.
- ๋ก๊น ์ฌ์ฉํ๊ธฐ: ์ ํ๋ฆฌ์ผ์ด์ ๋์์ ์ถ์ ํ๊ณ ๋ฌธ์ ๋ฅผ ์ง๋จํ๊ธฐ ์ํด ๋ก๊น ์ ์ฌ์ฉํ์ญ์์ค.
- ์ ํ๋ฆฌ์ผ์ด์ ๋ณด์ ๊ฐํํ๊ธฐ: ๊ณต๊ฒฉ์ผ๋ก๋ถํฐ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ณดํธํ๊ธฐ ์ํด ์ ์ ํ ๋ณด์ ์กฐ์น๋ฅผ ๊ตฌํํ์ญ์์ค.
- ์ ํ๋ฆฌ์ผ์ด์ ๋ชจ๋ํฐ๋งํ๊ธฐ: ์ฑ๋ฅ ๋ฌธ์ ์ ์ค๋ฅ๋ฅผ ๊ฐ์งํ๊ธฐ ์ํด ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ชจ๋ํฐ๋งํ์ญ์์ค. Prometheus๋ Grafana์ ๊ฐ์ ๋๊ตฌ๋ฅผ ๋ชจ๋ํฐ๋ง์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
๊ธ๋ก๋ฒ ํ๊ฒฝ์์์ ์คํ๋ง ๊ฐ๋ฐ
์คํ๋ง ๊ฐ๋ฐ์ ์ ์ธ๊ณ์ ์ผ๋ก ๋๋ฆฌ ์ฑํ๋๊ณ ์์ต๋๋ค. ๊ธ๋ก๋ฒ ์ฌ์ฉ์๋ฅผ ์ํ ์คํ๋ง ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฐ๋ฐํ ๋๋ ๋ค์ ์ฌํญ์ ๊ณ ๋ คํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค:
- ๊ตญ์ ํ(i18n) ๋ฐ ํ์งํ(l10n): ์ฌ๋ฌ ์ธ์ด์ ๋ฌธํ๋ฅผ ์ง์ํ๋๋ก ์ ํ๋ฆฌ์ผ์ด์ ์ ์ค๊ณํ์ญ์์ค. ์คํ๋ง์ i18n ๋ฐ l10n์ ์ํ ๋ฐ์ด๋ ์ง์์ ์ ๊ณตํฉ๋๋ค. ์๋ฅผ ๋ค์ด, ์คํ๋ง์ `MessageSource` ์ธํฐํ์ด์ค๋ฅผ ์ฌ์ฉํ๋ฉด ํ ์คํธ ๋ฉ์์ง๋ฅผ ์ธ๋ถํํ๊ณ ๋ค๋ฅธ ๋ก์ผ์ผ์ ๋ํด ๋ค๋ฅธ ๋ฒ์ญ์ ์ ๊ณตํ ์ ์์ต๋๋ค.
- ์๊ฐ๋: ๋ค๋ฅธ ์์น์ ์ฌ์ฉ์์๊ฒ ๋ ์ง์ ์๊ฐ์ด ์ ํํ๊ฒ ํ์๋๋๋ก ์๊ฐ๋๋ฅผ ์ฌ๋ฐ๋ฅด๊ฒ ์ฒ๋ฆฌํ์ญ์์ค. ์๋ฐ์ `java.time` ํจํค์ง๋ ์๊ฐ๋์ ๋ํ ํฌ๊ด์ ์ธ ์ง์์ ์ ๊ณตํฉ๋๋ค.
- ํตํ: ๋ค๋ฅธ ์ง์ญ์ ๋ง๋ ์ ์ ํ ํตํ ํ์๊ณผ ๊ธฐํธ๋ฅผ ์ฌ์ฉํ์ญ์์ค. ์๋ฐ์ `java.util.Currency` ํด๋์ค๋ ํตํ์ ๋ํ ์ ๋ณด๋ฅผ ์ ๊ณตํฉ๋๋ค.
- ๋ฐ์ดํฐ ํ์: ๋ ์ง ํ์, ์ซ์ ํ์ ๋ฑ ๋ค๋ฅธ ๋ฌธํ๊ถ์ ๋ง๋ ์ ์ ํ ๋ฐ์ดํฐ ํ์์ ์ฌ์ฉํ์ญ์์ค. ์๋ฐ์ `java.text.DateFormat` ๋ฐ `java.text.NumberFormat` ํด๋์ค๋ฅผ ์ฌ์ฉํ์ฌ ๋ค๋ฅธ ๋ก์ผ์ผ์ ๋ฐ๋ผ ๋ฐ์ดํฐ๋ฅผ ํ์ํํ ์ ์์ต๋๋ค.
์๋ฅผ ๋ค์ด, ๋ฏธ๊ตญ ์ฌ์ฉ์์๊ฒ ๋ ์ง๋ฅผ ํ์ํ ๋๋ `MM/dd/yyyy` ํ์์ ์ฌ์ฉํ ์ ์์ง๋ง, ์ ๋ฝ ์ฌ์ฉ์๋ `dd/MM/yyyy` ํ์์ ๊ธฐ๋ํ ์ ์์ต๋๋ค. ๋ง์ฐฌ๊ฐ์ง๋ก, ์ผ๋ถ ๊ตญ๊ฐ์์๋ ์ซ์์ ์์์ ๊ตฌ๋ถ ๊ธฐํธ๋ก ์ผํ๋ฅผ ์ฌ์ฉํ๊ณ ๋ค๋ฅธ ๊ตญ๊ฐ์์๋ ๋ง์นจํ๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์คํ๋ง ๊ฐ๋ฐ์ ๋ฏธ๋
์คํ๋ง ํ๋ ์์ํฌ๋ ์ํํธ์จ์ด ๊ฐ๋ฐ์ ๋ณํํ๋ ํ๊ฒฝ์ ๋ง์ถฐ ๊ณ์ํด์ ์งํํ๊ณ ์ ์ํ๊ณ ์์ต๋๋ค. ์คํ๋ง ๊ฐ๋ฐ์ ์ฃผ์ ๋ํฅ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ๋ฐ์ํ ํ๋ก๊ทธ๋๋ฐ: ๊ฐ๋ฐ์๋ค์ด ๋ ํ์ฅ ๊ฐ๋ฅํ๊ณ ์๋ต์ฑ์ด ๋ฐ์ด๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ๊ณ ์ ํจ์ ๋ฐ๋ผ ๋ฐ์ํ ํ๋ก๊ทธ๋๋ฐ์ ์ฑํ์ด ์ฆ๊ฐํ๊ณ ์์ต๋๋ค.
- ํด๋ผ์ฐ๋ ๋ค์ดํฐ๋ธ ๊ฐ๋ฐ: ๋ ๋ง์ ์กฐ์ง์ด ์ ํ๋ฆฌ์ผ์ด์ ์ ํด๋ผ์ฐ๋๋ก ์ด์ ํจ์ ๋ฐ๋ผ ์คํ๋ง ํด๋ผ์ฐ๋์ ์ค์์ฑ์ด ์ ์ ๋ ์ปค์ง๊ณ ์์ต๋๋ค.
- ์๋ฒ๋ฆฌ์ค ์ปดํจํ : ์คํ๋ง์ AWS Lambda ๋ฐ Azure Functions์ ๊ฐ์ ํ๋ซํผ์์ ์๋ฒ๋ฆฌ์ค ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฐ๋ฐํ๋ ๋ฐ ์ฌ์ฉ๋๊ณ ์์ต๋๋ค.
- GraalVM: GraalVM์ ์๋ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ค์ดํฐ๋ธ ์ด๋ฏธ์ง๋ก ์ปดํ์ผํ ์ ์๋ ๊ณ ์ฑ๋ฅ ๋ค๊ตญ์ด ๊ฐ์ ๋จธ์ ์ ๋๋ค. ์ด๋ ์คํ๋ง ์ ํ๋ฆฌ์ผ์ด์ ์ ์์ ์๊ฐ๊ณผ ์ฑ๋ฅ์ ํฌ๊ฒ ํฅ์์ํฌ ์ ์์ต๋๋ค.
๊ฒฐ๋ก
์คํ๋ง ํ๋ ์์ํฌ๋ ์ํฐํ๋ผ์ด์ฆ ์๋ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ๊ธฐ ์ํ ๊ฐ๋ ฅํ๊ณ ๋ค์ฌ๋ค๋ฅํ ๋๊ตฌ์ ๋๋ค. ์ด ๊ฐ์ด๋์์ ๋ค๋ฃฌ ํต์ฌ ๊ฐ๋ , ๋ชจ๋ฒ ์ฌ๋ก ๋ฐ ๊ณ ๊ธ ๊ธฐ์ ์ ๋ง์คํฐํจ์ผ๋ก์จ, ์ฌ๋ฌ๋ถ์ ์๋ จ๋ ์คํ๋ง ๊ฐ๋ฐ์๊ฐ ๋์ด ๊ณ ํ์ง์ ํ์ฅ ๊ฐ๋ฅํ๊ณ ์ ์ง๋ณด์ํ๊ธฐ ์ฌ์ด ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ ์ ์์ต๋๋ค. ๊ณ์ ๋ฐฐ์ฐ๊ณ , ์ต์ ๋ํฅ์ ํ์ ํ๋ฉฐ, ์คํ๋ง ์ํ๊ณ์ ํ์ ๋ฐ์๋ค์ด์ญ์์ค.