spring6
jdk17
Framework
틀 제공/ 틀이 정해져있다. 이미 구현되어있는 편의 기능을 제공해준다.
기존 jsp에선 객체 조립기를 이용해서 의존성을 직접 주입해줬다.
개발하기 편리한 틀을 제공해줌
spring-webmvc : 스프링에서 제공하는 틀JPA(Java Persistence API - ORM 표준 설계)
스프링 데이터 - 데이터 처리를 추상화 시켜둠
스프링 시큐리티 - 인증(로그인), 인가(페이지 통제)
스프링 배치 - 콘솔, 일괄처리 지원
🔹스프링 데이터 : 적은 양의 코드로 데이터 연동을 처리할 수 있도록 도와주는 프레임워크이다. JPA, 몽고DB, 레디스 등 다양한 저장소 기술을 지원한다.
🔹스프링 시큐리티 : 인증/인가와 관련된 프레임워크로서 웹 접근 제어, 객체 접근 제어, DB - 오픈 ID - LDAP 등 다양한 인증 방식, 암호화 기능을 제공한다.
🔹스프링 배치 : 로깅/추적, 작업 통계, 실패 처리 등 배치 처리에 필요한 기본 기능을 제공한다.
spring-context -> 의존성
1) maven 프로젝트 생성
2) maven repository에서 의존성 찾아서 pom.xml내의 dependencies에 추가

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.1.10</version>
</dependency>
spring6 - JDK 컴파일 버전 17
추가 할 의존성은 maven과 같이 Spring Context를 추가하면 된다.
build.gradle에 추가 + UTF8, 인텔리제이에 탑재된 Gradle로 세팅 변경
implementation 'org.springframework:spring-context:6.1.10'
스프링의 핵심 기능은 객체를 생성하고 초기화 하는 것이다. 이와 관련된 기능은
ApplicationContext라는 인터페이스에 정의되어 있다.
AnnotationConfigApplicationContext 클래스는 이 인터페이스를 알맞게 구현한 클래스 중 하나이다. AnnotationConfigApplicationContext 클래스는 자바 클래스에서 정보를 읽어와 객체 생성과 초기화를 수행한다.
XML 파일이나 그루비 설정 코드를 이용해서 객체 생성/초기화를 수행하는 클래스도 존재한다.
🔸AnnotationConfigApplicationContext 클래스 계층도 일부

🔼 BeanFactory / ApplicationContext: 스프링 컨테이너
ApplicationContext(또는 BeanFactory)는 빈 객체의 생성, 초기화, 보관, 제거 등을 관리하고 있어 ApplicationContext를 컨테이너(Container)라고도 부른다.
BeanFactory 인터페이스는 객체 생성과 검색에 대한 기능을 정의한다. 예를 들어 생성된 객체를 검색하는데 필요한 getBean() 메서드가 BeanFactory에 정의되어 있다. 객체를 검색하는 것 이외에 싱글톤/프로토타입 빈인지 확인하는 기능도 제공한다.
ApplicationContext 인터페이스는 메시지, 프로필/환경 변수 등을 처리할 수 있는 기능을 추가로 정의한다.
AnnotationConfigApplicationContext를 비롯해 계층도의 가장 하단에 위치한 세개의 클래스는 BeanFactory와 ApplicationContext에 정의된 기능의 구현을 제공한다.

🔼 가변인자.. 설정 클래스 여러개를 넣을 수 있다. 패키지를 지정하는 것도 가능

◾ 어떤 구현 클래스를 사용하든, 각 구현 클래스는 설정 정보로부터 빈(Bean)이라고 불리는 객체를 생성하고 그 객체를 내부에 보관한다. 그리고 getBean() 메서드를 실행하면 해당하는 빈 객체를 제공한다.
public class Greeter {
public void hello(String name){
System.out.println("Hello "+name+"!!!");
}
}
//AppCtx.java 설정클래스
//설정 클래스 - 스프링 컨테이너가 관리할 객체를 정의하고 설정하는 역할
@Configuration
public class AppCtx {
@Bean //스프링 컨테이너가 관리 해야할 객체임을 알려주는 역할(Bean)
public Greeter greeter(){
return new Greeter();
}
}
//Ex01
public class Ex01 {
@Test
void test1(){
//스프링 컨테이너 객체 생성
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppCtx.class);
//매개변수에 스프링이 관리해야할 설정 클래스를 알려준다.
//위 컨테이너 안에 현재 Greeter객체가 담겨있다.
Greeter greet = ctx.getBean("greeter", Greeter.class);
greet.hello("성준");
ctx.close();
}
}
//hello 성준 출력!
1) 싱글톤 방식으로 객체를 관리함(동일 객체)

동일 객체가 greet과 greet2에 대입된다!
◾ 별도 설정을 하지 않을 경우 스프링은 한 개의 빈 객체만을 생성하며, 이 때 빈 객체는 "싱글톤(singleton) 범위를 갖는다"고 표현한다.
싱글톤은 단일 객체(single object)를 의미하는 단어로 스프링은 기본적으로 한 개의 @Bean 애노테이션에 대해 한 개의 빈 객체를 생성한다.

싱글톤으로 기본 관리하므로 객체가 한개만 있는 경우가 많다. 그러므로 Class 클래스만 있어도 찾는데 문제 없음 ‼🙆♀️
결론! Greeter 타입의 빈이 하나만 존재하면 이름을 명시하지 않고도 타입만으로 빈을 조회할 수 있다.
1) 의존(Dependency)
2) DI를 통한 의존 처리
package spring;
import java.time.LocalDateTime;
public class MemberRegisterService {
private MemberDao memberDao;
public MemberRegisterService(MemberDao memberDao) {
this.memberDao = memberDao;
}
public long regist(RegisterRequest req) {
Member member = memberDao.selectByEmail(req.getEmail());
if (member != null) {
throw new DuplicateMemberException("dup.email " + req.getEmail());
}
Member newMember = new Member(req.getEmail(), req.getPassword(), req.getName(), LocalDateTime.now());
memberDao.insert(newMember);
return newMember.getId();
}
}
package spring;
public class ChangePasswordService {
private MemberDao memberDao;
public void changePassword(String email, String oldPwd, String newPwd) {
Member member = memberDao.selectByEmail(email);
if (member == null)
throw new MemberNotFoundException();
member.changePassword(oldPwd, newPwd);
memberDao.update(member);
}
public void setMemberDao(MemberDao memberDao) {
this.memberDao = memberDao;
}
}
@Configuration
@Bean
3) DI와 의존 객체 변경의 유연함
➰로그인 & 회원가입 ➰

※SOLID
S - Single Responsibility Principal
- 단일 책임 원칙
하나의 클래스는 하나의 역할을 담당
#MemberDao클래스
public class MemberDao {
/*
DB에 저장하지 않고 임시 메모리에 저장
*/
private static Map<String, Member> members = new HashMap<>();
public void register(Member member) {
members.put(member.getEmail(),member);
}
public Member get(String email){
return members.get(email);
}
public List<Member> getList(){
List<Member> data = new ArrayList<>(members.values());
return data;
}
}
#JoinService클래스
public class JoinService {
private JoinValidator validator;
private MemberDao memberDao;
/*
//연관 관계 - 없어도 객체 생성 가능
//setter을 통한 주입
public void setValidator (JoinValidator validator) {
this.validator = validator;
}
*/
//의존관계 - 없으면 객체 생성 불가
//생성자를 통한 주입
public JoinService(JoinValidator validator, MemberDao memberDao) {
this.validator = validator;
this.memberDao = memberDao;
}
public void process(RequestJoin form){
validator.check(form); //joinService는 validator 객체와 form 객체를 의존하고있다.
// -> 의존성!!
//데이터 영구 저장 - DAO(Data Access Object)
Member member = Member.builder()
.email(form.getEmail())
.password(form.getPassword())
.userName(form.getUserName())
.regDt(LocalDateTime.now())
.build();
memberDao.register(member);
}
}

객체 조립기에 필요한 의존성을 추가해주기만 하면 해당 의존성을 필요로 하는 곳에서 손 쉽게 반영될 수 있다.
#Assembler클래스
public class Assembler {
public MemberDao memberDao(){
return new MemberDao();
}
public JoinValidator joinValidator(){
return new JoinValidator();
}
public JoinService joinService(){
return new JoinService(joinValidator(),memberDao());
}
}
객체 조립기 사용🤹♂️

객체 조립기 내부에서 객체를 생성해준다!

🎀스프링이 대신해주는 객체 조립 시간 ~!
위에서 사용한 Assembler(객체 조립기 클래스)가 필요 없어진다.
#스프링 컨테이너가 관리할 객체를 정의하고 설정 하는 클래스 AppCtx2
@Configuration
public class AppCtx2 {
@Bean
public MemberDao memberDao(){
return new MemberDao();
}
@Bean
public JoinValidator joinValidator(){
JoinValidator joinValidator = new JoinValidator();
joinValidator.setMemberDao(memberDao());
return joinValidator;
}
@Bean
public JoinService joinService(){
return new JoinService(joinValidator(),memberDao());
}
}
# 컨테이너 객체 생성
public class Ex03 {
@Test
void test1(){
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppCtx2.class);
JoinService joinService = ctx.getBean(JoinService.class);
MemberDao memberDao = ctx.getBean(MemberDao.class);
RequestJoin form = RequestJoin.builder()
.email("user01@test.org")
.userName("사용자01")
.password("12345678")
.confirmPassword("12345678")
.build();
joinService.process(form);
memberDao.getList().forEach(System.out::println);
ctx.close();
}
}


설정 클래스에 Bean객체로 추가


똑같은 동작하는 걸 확인했다
📢📢하지만 객체가 생길때마다 @Bean으로 설정해서 넣어주게 되는것도 번거로운 일이 될수 있다. 설정해야할 객체가 100개라면 Bean객체 선언을 100개를 선언해야할 것..