@Component를 사용하면 @ComponentScan에 의해 자동으로 스캔되어 해당 클래스를 Bean으로 등록 해준다. 자동으로 등록하는 것이 좋다.
수동 등록하는 경우
기술적인 문제나 공통적인 관심사를 처리할 때 사용하는 객체들
공통 로그처리와 같은 비즈니스 로직을 지원하기 위한 부가 적이고 공통적인 기능 (기술 지원 Bean)
- 비즈니스 로직 Bean 보다는 그 수가 적기 때문에 수동으로 등록하기 부담스럽지 않습니다.
- 또한 수동등록된 Bean에서 문제가 발생했을 때 해당 위치를 파악하기 쉽다는 장점이 있습니다.
1) Bean 으로 등록하고자 하는 클래스 선언
2) 위에 @Bean Annotation 추가
3) Bean을 등록하는 메서드가 속한 해당 클래스에 @Configuration을 설정
@Configuration
public class PasswordConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
Spring 서버 실행 시 IoC 컨테이너에 Bean으로 저장된다.

하나의 인터페이스를 2개의 클래스로 구현해서 Bean으로 등록할 수 있다

그러나 그 인터페이스를 @Autowired (주입 받기) 하려고 하면 에러가 발생한다
둘 중 무엇을 주입할지 몰라서 우리에게 묻는다
1) 테스트 시 등록된 Bean의 이름을 명시해준다. (= 구현한 객체 이름)
@Autowired
Food pizza; // 이미 구현된 객체 이름과 동일
@Autowired
Food chicken;
Bean Type으로 찾았을 때 연결이 되지 않으면 Bean Name(pizza, chicken)으로 찾는다.
2) 구현체 둘 중 하나에게 @Primary 부여 > 우선 사용
@Component
@Primary
public class Chicken implements Food {
@Override
public void eat() {
System.out.println("치킨을 먹습니다.");
}
}
3) @Qualifier로 이름을 지정한 구현체를 지정 > 우선 사용
1. Pizza 구현 시 클래스 위에 @Qualifier("pizza") 작성
@SpringBootTest
public class BeanTest {
@Autowired
@Qualifier("pizza") // 2. 주입할 객체 위에 작성
Food food;
}
Primary / Qualifier 중 우선순위는 Qualifier가 더 높다
그러나 주입받고자 하는 곳에 Qualifier를 무조건 작성해야 한다.
즉, 많이 사용하는 객체에 Primary, 지역적으로 사용하는 객체에 Qualifier를 붙이는 게 좋다

비연결성 : 채팅이나 게임 같은 것들을 하지 않는 이상 서버와 클라이언트는 실제로 연결되어 있지 않다. 리소스를 절약하기 위해서
무상태 : 서버가 클라이언트의 상태를 저장하지 않는다
연결된 것처럼 느낄 수 있게끔 URL을 통해 구현하고 있다.
그렇다면 다음 페이지에서는 내가 로그인한 것을 어떻게 알고 있을까?

- 사용자가 로그인 요청을 보낸다.
- 서버는 DB의 유저 테이블을 확인하여 ID, Password를 대조한다.
- 실제 유저테이블의 정보와 일치한다면 인증을 통과한 것으로 보고 “세션 저장소”에 해당 유저가 로그인 되었다는 정보를 넣습니다.
- 세션 저장소에서는 유저의 정보와는 관련 없는 난수인 session-id를 발급합니다.
- 서버는 로그인 요청의 응답으로 session-id를 내어줍니다.
- 클라이언트는 그 session-id를 쿠키라는 저장소에 보관하고 앞으로의 요청마다 세션아이디를 같이 보냅니다. (주로
HTTP header에 담아서 보냅니다!)- 클라이언트의 요청에서 쿠키를 발견했다면 서버는 세션 저장소에서 쿠키를 검증합니다.
- 만약 유저정보를 받아왔다면 이 사용자는 로그인이 되어있는 사용자겠죠?
- 이후에는 로그인 된 유저에 따른 응답을 내어줍니다.

HTTP header에 실어 서버가 클라이언트를 식별합니다.
- 사용자가 로그인 요청을 보냅니다.
- 서버는 DB의 유저 테이블을 확인하여 ID, Password를 대조한다.
- 실제 유저테이블의 정보와 일치한다면 인증을 통과한 것으로 보고 유저의 정보를 JWT로 암호화 해서 내보냅니다.
- 서버는 로그인 요청의 응답으로 jwt 토큰을 내어줍니다.
- 클라이언트는 그 토큰을 저장소에 보관하고 앞으로의 요청마다 토큰을 같이 보냅니다.
- 클라이언트의 요청에서 토큰을 발견했다면 서버는 토큰을 검증합니다.
- 이후에는 로그인 된 유저에 따른 응답을 내어줍니다.
세션 저장소가 따로 없다는 것이 가장 큰 차이이다.
JWT는 토큰 자체를 브라우저에 던지기 때문에 더 효율적일 수 있다.
클라이언트에 저장될 목적으로 생성한 작은 정보를 답은 파일

- 클라이언트가 서버에 1번 요청
- 서버가 세션ID 를 생성하고, 쿠키에 담아 응답 헤더에 전달
- 세션 ID 형태: "SESSIONID = 12A345"
- 클라이언트가 쿠키에 세션ID를 저장 ('세션쿠키')
- 클라이언트가 서버에 2번 요청
- 쿠키값 (세션 ID) 포함하여 요청
- 서버가 세션ID 를 확인하고, 1번 요청과 같은 클라이언트임을 인지

public static void addCookie(String cookieValue, HttpServletResponse res) {
try {
cookieValue = URLEncoder.encode(cookieValue, "utf-8").replaceAll("\\+", "%20");
// Cookie Value 에는 공백이 불가능해서 encoding 진행
Cookie cookie = new Cookie(AUTHORIZATION_HEADER, cookieValue); // Name-Value 생성자의 객체 생성
// AUTHORIZATION_HEADER는 위에 생성된 String 상수
// 경로, 만료시간 설정
cookie.setPath("/");
cookie.setMaxAge(30 * 60);
// Response 객체에 Cookie 추가
res.addCookie(cookie);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e.getMessage());
}
}
@GetMapping("/get-cookie")
public String getCookie(@CookieValue(AUTHORIZATION_HEADER) String value) {
System.out.println("value = " + value);
return "getCookie : " + value;
}
@CookieValue("Cookie의 Name") : Cookie의 Name 정보를 토대로 Cookie의 Value를 가져온다세션 ID를 간편하게 만들 수 있다.
@GetMapping("/create-session")
public String createSession(HttpServletRequest req) {
// 세션이 존재할 경우 세션 반환, 없을 경우 새로운 세션을 생성한 후 반환
HttpSession session = req.getSession(true);
// 세션에 저장될 정보 Name - Value 를 추가합니다.
session.setAttribute(AUTHORIZATION_HEADER, "Robbie Auth");
return "createSession";
}
@GetMapping("/get-session")
public String getSession(HttpServletRequest req) {
// 세션이 존재할 경우 세션 반환, 없을 경우 null 반환, false 옵션 주기
HttpSession session = req.getSession(false);
String value = (String) session.getAttribute(AUTHORIZATION_HEADER);
// 가져온 세션에 저장된 Value 를 Name 을 사용하여 가져옵니다.
System.out.println("value = " + value);
return "getSession : " + value;
}