-
Notifications
You must be signed in to change notification settings - Fork 10
[21기_최근호] spring tutorial 미션 제출합니다. #13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: WithFortuna
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
/gradlew text eol=lf | ||
*.bat text eol=crlf | ||
*.jar binary |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
HELP.md | ||
.gradle | ||
build/ | ||
!gradle/wrapper/gradle-wrapper.jar | ||
!**/src/main/**/build/ | ||
!**/src/test/**/build/ | ||
|
||
### STS ### | ||
.apt_generated | ||
.classpath | ||
.factorypath | ||
.project | ||
.settings | ||
.springBeans | ||
.sts4-cache | ||
bin/ | ||
!**/src/main/**/bin/ | ||
!**/src/test/**/bin/ | ||
|
||
### IntelliJ IDEA ### | ||
.idea | ||
*.iws | ||
*.iml | ||
*.ipr | ||
out/ | ||
!**/src/main/**/out/ | ||
!**/src/test/**/out/ | ||
|
||
### NetBeans ### | ||
/nbproject/private/ | ||
/nbbuild/ | ||
/dist/ | ||
/nbdist/ | ||
/.nb-gradle/ | ||
|
||
### VS Code ### | ||
.vscode/ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,192 @@ | ||
# spring-tutorial-21st | ||
CEOS back-end 21st spring tutorial project | ||
|
||
# 1주차 | ||
|
||
## POJO | ||
|
||
: 특정 프레임워크나 라이브러리에 의존하지 않는 순수 자바 코드 | ||
|
||
--- | ||
|
||
## Spring | ||
|
||
: 자바 기반 객체지향적으로 서버 설계를 편리하게 도와주는 프레임워크. 주로 빈을 통해 객체를 관리하는 컨테이너 역할 | ||
|
||
- **객체지향 5원칙** | ||
- **S**: Single Responsibility ⇒ 책임분리(AOP, 관점지향 프로그래밍) | ||
- **O**: Open closed principle ⇒ 인터페이스에 의존하고 구현체에 의존하지 않는다(PSA, 서비스 추상화) | ||
- **L**: 리스코프 치환법칙 ⇒ 상속할 때 주의해라. (자식은 부모의 기능을 온전히 수행 가능해야함) | ||
|
||
**ex1)** 잘못된 상속: Rectangle로 Square 인스턴스를 받아도 밑변과 높이를 서로 다르게 설정이 불가능함 | ||
Rectangle ← Square | ||
|
||
// 코드 | ||
Rectange rec = new Square(); | ||
rec.setHeight(10); | ||
rec.setWidth(15); // !!!!!!!!!!!!오류 발생. width, height 모두 15로 설정됨. | ||
|
||
**ex2)** 잘한 상속: | ||
List ← ArrayList | ||
← LinkedList | ||
|
||
- **I**: Inversion of Control ⇒ 스프링 컨테이너가 객체 관리 | ||
- **D**: Dependency Injection ⇒ 관리 중인 객체를 삽입 | ||
|
||
--- | ||
|
||
**Q. 스프링이 POJO 프레임워크라고 함은 무슨 의미?** | ||
|
||
⇒ 개발자의 선택에 따라 스프링에 의존할지 안할지 결정 가능 (POJO 객체를 쓸지 말지 선택 가능) | ||
|
||
/** POJO 코드 | ||
* 스프링 없어도 돌아감 | ||
*/ | ||
|
||
@Service | ||
public class MemberService { | ||
private MemberRepository memberRepository; | ||
//... | ||
} | ||
|
||
//NOT POJO | ||
@Controller | ||
public class MemberController { | ||
@GetMapping("/members") | ||
public String getMembers() {} | ||
} | ||
WithFortuna marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
--- | ||
|
||
## AOP (Aspect Oriented Programming, 관점 지향 프로그래밍) | ||
|
||
: 비즈니스 로직과 관리 로직 관심사를 분리 | ||
|
||
**ex)** Service 계층에서 (비즈니스 로직, 트랜잭션 관리 코드)를 분리 | ||
|
||
--- | ||
|
||
## PSA (Portable Service Abstraction) | ||
|
||
: 특정 기술에 종속적이지 않은 설계 = 인터페이스에 의존하고 구현체에 의존 X | ||
|
||
**ex)** 데이터 접근 기술 중 JPA, JDBC 로 변경하여도 코드의 변경은 최소화된다. | ||
`PlatformTransactionManager` | ||
- JpaTransactionManager (JPA) | ||
- DataSourceTransactionManager (JDBC) | ||
|
||
--- | ||
|
||
## Spring Boot | ||
|
||
- 내장 톰캣 | ||
- 의존성 관리 | ||
- 설정 자동화 | ||
- 모니터링 (성능 측정, 메트릭 확인) | ||
|
||
--- | ||
|
||
## 1. 스프링 빈 | ||
|
||
- **의미:** 스프링 컨테이너에서 생성과 소멸을 관리하는 **싱글톤 객체** | ||
싱글톤 객체: 동일한 인스턴스로 같은 메모리 점유 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 싱글톤 객체의 설명을 보고 static 클래스와 spring bean의 차이점이 궁금해서 찾아보았는데 잘 설명되어있는 것 같아 첨부합니다~ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 오.. 리뷰 보고나니까 저도 궁금해져서 링크 보고 왔습니다 |
||
|
||
- **생명주기:** | ||
객체 생성 → 의존성 주입 → 초기화 → 사용 중 → 소멸 | ||
|
||
**Q. @PostConstruct가 적용되는 시점은?** | ||
⇒ 초기화 단계의 **마지막**에 호출된다. | ||
객체가 생성(메모리 힙에 할당), 의존성이 주입되고 필요한 설정들도 끝난 초기화의 마지막 단계. | ||
(이때 개발자가 원하는 추가 설정이 가능) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 어떤 추가 설정이 가능한가요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 테스트데이터를 초기화하거나 간단한 캐싱작업에도 활용할 수 있다고 합니다 |
||
|
||
--- | ||
|
||
## 2. 스프링 빈 등록 방법 | ||
|
||
- `@Bean`을 사용한 직접 등록 | ||
WithFortuna marked this conversation as resolved.
Show resolved
Hide resolved
|
||
- `@Component` 사용 (`@Service`, `@Repository`, `@Controller`) | ||
- `@ComponentScan(basePackages = " ")` | ||
: 지정 패키지(없다면 현재 패키지) 하위의 @Component를 찾으면 자동 빈 등록 | ||
|
||
--- | ||
|
||
## 3. 어노테이션 | ||
|
||
- **기능** | ||
- 메타 데이터 | ||
ex) `@Override` | ||
- 특정 기능을 가짐 | ||
ex) `@Component`, `@PostConstruct` | ||
|
||
// 코드 | ||
@Target(ElementType.???) // TYPE, METHOD, FIELD | ||
@Retention(RetentionPolicy.???) // RUNTIME, CLASS, SOURCE | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 저는 해당 부분을 조사할 때 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. RetentionPolicy.CLASS는 저도 이게 굳이 왜 필요한지 이해가 잘 안갔었는데 덕분에 배워갑니다 👍 |
||
public @interface CustomAnnotation {} | ||
|
||
--- | ||
|
||
## 4. 스프링 Context 구조 | ||
|
||
- **BeanDefinitionRegistry**와 **BeanFactory** 상속관계 | ||
|
||
`DefaultListableBeanFactory` (클래스, 구현체) | ||
→ *BeanFactory 인터페이스* | ||
→ *BeanDefinitionRegistry 인터페이스* | ||
|
||
`AnnotationConfigApplicationContext` (자식) | ||
→ `GenericApplicationContext` (부모) | ||
→ *BeanFactory 인터페이스* | ||
→ *BeanDefinitionRegistry 인터페이스* | ||
|
||
// 코드 | ||
public class GenericApplicationContext implements BeanFactory, BeanDefinitionRegistry { | ||
private DefaultListableBeanFactory beanFactory; | ||
|
||
public Object getBean() { | ||
beanFactory.getBean(); // 위임 | ||
} | ||
} | ||
WithFortuna marked this conversation as resolved.
Show resolved
Hide resolved
Comment on lines
+136
to
+148
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 저도 궁금해서 찾아봤었는데
Comment on lines
+142
to
+148
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 코드 예시 들어주신거 너무 좋은데요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 오 질문이 날카롭습니다..
보통 조합과 위임이라고 표현하는 것 같습니다 |
||
|
||
--- | ||
|
||
## 5. 테스트 코드 | ||
|
||
### 1. **단위 테스트** | ||
|
||
: 외부 환경과는 분리된 순수한 코드 로직을 대상으로 검증 | ||
|
||
// 코드 | ||
@ExtendWith(MockitoExtension.class) | ||
class MemberServiceTest { | ||
@Mock | ||
private MemberRepository memberRepository; | ||
|
||
@InjectMocks | ||
private MemberService memberService; | ||
|
||
@Test | ||
void findById() { | ||
// given | ||
Member member = new Member(...); | ||
when(memberRepository.findById(1L)) | ||
.thenReturn(Optional.of(new Member("olaf"))); | ||
|
||
// when | ||
Member findMember = memberService.findById(1L); | ||
|
||
// then | ||
Assertions.assertThat(findMember.getName()).isEqualTo("olaf"); | ||
} | ||
} | ||
|
||
--- | ||
|
||
### 2. **통합 테스트** | ||
|
||
: API 요청, DB 연결과 같은 외부 환경을 포함하여 시스템의 전체적인 동작을 검증 | ||
|
||
// 코드 | ||
@SpringBootTest // 스프링 환경에서 통합테스트 | ||
@AutoConfigureMockMvc // API 호출 테스트 | ||
class ApiTest { | ||
} | ||
WithFortuna marked this conversation as resolved.
Show resolved
Hide resolved
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
plugins { | ||
id 'java' | ||
id 'org.springframework.boot' version '3.4.3' | ||
id 'io.spring.dependency-management' version '1.1.7' | ||
} | ||
|
||
group = 'com.ceos21' | ||
version = '0.0.1-SNAPSHOT' | ||
|
||
java { | ||
toolchain { | ||
languageVersion = JavaLanguageVersion.of(17) | ||
} | ||
} | ||
|
||
repositories { | ||
mavenCentral() | ||
} | ||
|
||
dependencies { | ||
implementation 'org.springframework.boot:spring-boot-starter-web' | ||
implementation 'org.springframework.boot:spring-boot-starter-data-jpa' | ||
//h2 | ||
runtimeOnly 'com.h2database:h2' | ||
//lombok | ||
compileOnly 'org.projectlombok:lombok' | ||
annotationProcessor 'org.projectlombok:lombok' | ||
|
||
testImplementation 'org.springframework.boot:spring-boot-starter-test' | ||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher' | ||
} | ||
|
||
tasks.named('test') { | ||
useJUnitPlatform() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
distributionBase=GRADLE_USER_HOME | ||
distributionPath=wrapper/dists | ||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip | ||
networkTimeout=10000 | ||
validateDistributionUrl=true | ||
zipStoreBase=GRADLE_USER_HOME | ||
zipStorePath=wrapper/dists |
Uh oh!
There was an error while loading. Please reload this page.