스프링

  1. 스프링 생태계
  • 필수 : 스프링 프레임워크 / 스프링부트
  • 선택
    • 스프링 데이터 : 디비사용편하게
    • 스프링 세션 / 스프링 시큐리티 / 스프링 배치
    • 스프링 rest docs : api문서를 편하게

 

  1. 스프링 부트
  • 스프링을 편리하게 사용할 수 있도록 지원
  • 톰캣같은 웹 서버를 내장하여 별도의 웹 서버 설치않아도 됨
  • 단독으로 실행할 수 있는 스프링 애플리케이션 쉽게 생성
  • 손쉬운 빌드 구성을 위한 starter 종속성 제공 : 라이브러리에서 하나만 가져오는 것이 아닌 그 하위의 것들도 함께 가져옴
  • 스프링 프레임워크 버전에 맞는 외부 라이브러리를 가져옴
  • 메트릭, 상태확인, 외부 구성 같은 프로덕션 준비 기능 제공
  • 관례에 의한 간결한 설정

 

  1. 스프링의 핵심
  • 자바언어 기반의 프레임워크
  • 자바언어의 가장 큰 특징 : 객체지향언어
  • 스프링은 객체지향언어가 가진 강력한 특징을 살려내는 프레임워크
  • 스프링은 좋은 객체 지향 애플리케이션을 개발할 수 있게 도와주는 프레임워크

 

  1. SOLID : 클린코드로 유명한 로버트 마틴이 좋은 객체지향설계의 5가지 원칙을 정리
  • SRP : 단일책임원칙
    • 한 클래스는 하나의 책임만 가져야한다.
    • 중요한 기준은 변경. 변경이 있을 때 파급효과가 적으면 단일책임원칙을 잘 따른 것.
  • OCP : 개방-폐쇄원칙
    • 소프트웨어 요소는 확장에는 열려있으나 변경에는 닫혀있어야한다.
    • 다형성활용하면 가능
    • EX) 인터페이스를 구현한 새로운 클래스를 하나 만들어서 새로운 기능을 구현
  • 인터페이스 = new 구현객체*
  • LSP : 리스코프 치환원칙
    • 프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야한다.
    • 다형성에서 하위클래스는 인터페이스 규약을 다 지켜야 한다는 것.
  • ISP : 인터페이스 분리 원칙
    • 특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다.
  • DIP : 의존관계 역전 원칙
    • "추상화에 의존해야지, 구체화에 의존하면 안된다." : 구현클래스에 의존하지 말고, 인터페이스에 의존하라

'JAVA' 카테고리의 다른 글

[Spring] MultipartHttpServletRequest 오류  (0) 2022.05.12
[JSP] 자바빈 관련 액션태그  (0) 2021.07.18
Spring 05 : AOP  (0) 2021.05.18
Spring 04 : 스프링 DB 접근  (0) 2021.05.18
Spring 03 : 스프링 빈과 의존관계  (0) 2021.05.18

AOP

  • 관점 지향 프로그래밍
  • 어떤 로직을 기준으로 핵심적인 관점, 부가적인 관점으로 나누어서 보고 그 관점을 기준으로 각각 모듈화하겠다는 것
    • 모든 메소드의 호출 시간을 측정하려고 할 때
    • 공통 관심 사항(cross-cutting concern) vs 핵심 관심 사항(core concern)
  • AOP가 필요한 상황
long start = System.currentTimeMillis(); 
try{
	validateDuplicateMember(member); 
    memberRepository.save(member); 
    return member.getId(); 
}finally {
    	long finish = System.currentTimeMillis(); 
        long timeMs=finish-start; 
        System.out.println("join = " + timeMs + "ms"); 
}

AOP를 사용하지 않는다면 메소드 호출시간을 측정해주는 것을 포함시켜야한다.

 

시간측정 AOP 등록

@Aspect //이걸 적어야 aop사용가능 
@Component public class TimeTraceAop {

	@Around("execution(* hello.hellospring..*(..))") 
    public Object execute(ProceedingJoinPoint joinPoint) throws Throwable{
    	long start = System.currentTimeMillis(); 
        System.out.println("START: "+joinPoint.toString()); 
        try{ 
        	return joinPoint.proceed(); 
        }finally {
        	long finish = System.currentTimeMillis(); 
            long timeMs = finish-start; 
            System.out.println("END: "+joinPoint.toString()+" "+timeMs+"ms"); 
        } 
    } 
}

서비스 하위로 메소드 호출시간을 보고 싶을 때 : `@Around("execution( hello.hellospring.service.(..))")`

  • 회원가입, 회원 조회등 핵심 관심사항과 시간을 측정하는 공통 관심 사항을 분리.
  • 시간을 측정하는 로직을 별도의 공통 로직으로 생성.
  • 핵심 관심 사항 깔끔하게 유지가능.
  • 변경이 필요하면 이 로직만 변경하면 된다.
  • 원하는 적용 대상을 선택가능.

@Component가 아닌 직접 @Bean으로 참조 했을 때

@Configuration 
public class SpringConfig {
	@Bean 
    public TimeTraceAop timeTraceAop() {
    	return new TimeTraceAop(); 
    } 
}
  • 이 상태에서 @Around("execution(* hello.hellospring..*(..))")라고 한다면 자기 자신인 TimeTraceAop를 생성하는 코드인 SpringConfig의 timeTraceAop() 메서드도 AOP로 처리하게 된다. 따라서 순환참조 문제가 발생하게 된다.
  • 다음과 같이 AOP 대상에서 SpringConfig를 빼주면 된다.
  • @Around("execution(* hello.hellospring..*(..)) && !target(hello.hellospring.SpringConfig)")

 

Ctrl+Alt+L : 코드정렬

인프런 '스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술' 통해 학습 중.

스프링 데이터 엑세스

 

1. 순수 JDBC
2. 스프링 JdbcTemplate
3. JPA

 

H2 데이터베이스 설치 방법

 

1) ./h2.bat (mac에서는 ./h2.sh)
2) jdbc:h2:~/test로 DB 생성
3) ~/test.mv.db 파일 생성 확인
4) 이후부터 jdbc:h2:tcp://localhost/~/test로 접속

The Web Console server could not be started. Possible cause: another server is already running at XXX:8082

8082 포트가 겹쳐서 발생한 오류. 포트 죽여줘야함.

 

순수 JDBC

  • build.gradle 파일에 jdbc, h2 데이터베이스 관련 라이브러리 추가
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
runtimeOnly 'com.h2database:h2'
  • 스프링 부트 데이터베이스 연결 설정 추가 (resources/application.properties )
spring.datasource.url=jdbc:h2:tcp://localhost/~/test
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
  • pstmt = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS); : sequence라고 생각하자
  • spring config 변경
@Bean public MemberRepository memberRepository() {
	// return new MemoryMemberRepository(); 
	return new JdbcMemberRepository(dataSource);
}

 

스프링 통합 테스트

  • @SpringBootTest : 스프링 컨테이너와 테스트 함께 실행.
  • @Transactional : 테스트 케이스에 이 애노테이션이 있으면, 테스트 시작 전에 트랜잭션을 시작, 테스트 완료 후에 항상 롤백. 다음 테스트에 영향 주지않기 위해 사용. (DB에 데이터가 남지 않음)

 

스프링 JdbcTemplate

  • 스프링 JdbcTemplate과 MyBatis 같은 라이브러리는 JDBC API에서 본 반복 코드를 제거해준다. 하지만 SQL은 직접 작성.
  • 순수 JDBC와 환경설정은 같다.
  • spring config 변경
@Bean
public MemberRepository memberRepository() {
	// return new MemoryMemberRepository(); 
    // return new JdbcMemberRepository(dataSource); 
    return new JdbcTemplateMemberRepository(dataSource); 
}

 

JPA

  • 기존의 반복 코드는 물론이고, 기본적인 SQL도 JPA가 직접 만들어서 실행.
  • SQL과 데이터 중심의 설계에서 객체 중심의 설계로 패러다임을 전환 가능하게 해준다.
  • build.gradle 파일에 JPA, h2 데이터베이스 관련 라이브러리 추가
dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' 
    implementation 'org.springframework.boot:spring-boot-starter-web' 
    //implementation 'org.springframework.boot:spring-boot-starter-jdbc' 
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa' 
    runtimeOnly 'com.h2database:h2' 
    testImplementation('org.springframework.boot:spring-boot-starter-test') { 
    	exclude group: 'org.junit.vintage', module: 'junit-vintage-engine' 
    } 
}

spring-boot-starter-data-jpa 는 내부에 jdbc 관련 라이브러리를 포함

 

  • 스프링 부트에 JPA 설정 추가(resources/application.properties)
spring.jpa.show-sql=true //JPA가 생성하는 SQL을 출력 
spring.jpa.hibernate.ddl-auto=none //자동으로 테이블 생성하는 것 해제
  • member 클래스 엔티티매핑
@Entity 
public class Member {
	@Id @GeneratedValue(strategy = GenerationType.IDENTITY) //DB가 알아서 생성되게 한 것을 identity전략이라고 함.
    private Long id; 
    private String name;
  • JpaMemberRepository 생성 (JPQL 사용)
  • 서비스 계층에 트랜잭션 추가
  • spring config 변경
@Configuration 
public class SpringConfig { 
	private final DataSource dataSource; 
    private final EntityManager em; 
    public SpringConfig(DataSource dataSource, EntityManager em) {
    	this.dataSource = dataSource; this.em = em; 
    } 

	@Bean 
	public MemberService memberService() {
		return new MemberService(memberRepository());
	} 

	@Bean 
	public MemberRepository memberRepository() {
		// return new MemoryMemberRepository(); 
    	// return new JdbcMemberRepository(dataSource); 
   	 	// return new JdbcTemplateMemberRepository(dataSource); 
   		return new JpaMemberRepository(em); 
 	}
}

 

스프링 데이터 JPA

  • 리포지토리에 구현 클래스 없이 인터페이스 만으로 개발을 완료할 수 있다.
  • 기본 CRUD 기능도 스프링 데이터 JPA가 모두 제공
  • 앞의 JPA 설정을 그대로 사용
  • 스프링 데이터 JPA 회원 리포지토리(인터페이스) 생성
  • spring config 변경
@Configuration
public class SpringConfig {
	private final MemberRepository memberRepository;
    
    @Autowired
    public SpringConfig(MemberRepository memberRepository) {
    	this.memberRepository = memberRepository;
    } 
    
    @Bean 
    public MemberService memberService(){
    	return new MemberService(memberRepository);
    } 
}
  • 스프링 데이터 JPA가 SpringDatJpaMemberRepository 를 스프링 빈으로 자동 등록

인프런 '스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술' 통해 학습 중.

'JAVA' 카테고리의 다른 글

Spring 핵심 01 : 객체 지향 설계와 스프링  (0) 2021.05.18
Spring 05 : AOP  (0) 2021.05.18
Spring 03 : 스프링 빈과 의존관계  (0) 2021.05.18
Spring02 : 예제(회원관리)  (0) 2021.05.18
Spring 01 : 프로젝트 환경설정  (0) 2021.05.18

스프링 빈 등록방법

  1. 컴포넌트 스캔과 자동 의존관계 설정
  2. 자바 코드로 직접 스프링 빈 등록하기

컴포넌트 스캔과 자동 의존관계 설정

  • 회원 컨트롤러가 회원서비스와 회원 리포지토리를 사용할 수 있게 의존관계 준비
@Controller
public class MemberController {
    private final MemberService memberService;    

    @Autowired
    public MemberController(MemberService memberService) {
        this.memberService = memberService;
    }
}
  • 생성자 주입을 쓰는 것이 제일 좋다.
  • @Autowired : 스프링이 연관된 객체를 스프링 컨테이너에서 찾아서 넣어준다.
  • @Component : 이 애노테이션이 있으면 스프링 빈으로 자동 등록된다.
  • @Component / @Controller, @Service, @Repository
@Autowired
private MemberService memberService;
  • 필드주입 : 스프링이 뜰 때만 넣어주고 바꿀 수 있는 방법이 없다. 잘 안쓴다.

 

자바 코드로 직접 스프링 빈 등록

  • @Service, @Repository, @Autowired 애노테이션 제거 후 진행

SpringConfig.java 파일 생성

@Configuration
public class SpringConfig {

    @Bean
    public MemberService memberService(){
        return new MemberService(memberRepository());
    }
    @Bean
    public MemberRepository memberRepository(){
        return new MemoryMemberRepository();
    }
  }
  • 장점 : 정형화 되지 않거나, 상황에 따라 구현 클래스를 변경해야 할 경우 직접 스프링 빈을 등록하는 것이 더 편하다.
  • 아직 데이터 저장소가 정해지지 않았다는 가상의 시나리오를 정했기 때문에 직접 스프링 빈을 등록하는 것으로 한다.

보충

  • thymeleaf : JSP와 달리 Servlet으로 변환X, 비즈니스 로직과 분리되어 View에 집중.
  • 스프링부트에서는 JSP 자동 설정 지원X. JSP는 jar패키징 불가하여 war패키징해야한다.
  • get : 주로 조회할 때 / post : 폼에 등록할 때

jar

  • 자바 프로젝트를 압축한 파일

war

  • 웹 관련 자원만 포함, 웹 어플리케이션 압축 파일 포맷
  • JAR 포맷과 달리 WEB-INF 및 META-INF 디렉토리로 사전 정의 된 구조를 사용
  • WAR파일을 실행하려면 Tomcat, Weblogic, Websphere 등의 웹 서버 (WEB)또는 웹 컨테이너(WAS)가 필요

인프런 '스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술' 통해 학습 중.

'JAVA' 카테고리의 다른 글

Spring 핵심 01 : 객체 지향 설계와 스프링  (0) 2021.05.18
Spring 05 : AOP  (0) 2021.05.18
Spring 04 : 스프링 DB 접근  (0) 2021.05.18
Spring02 : 예제(회원관리)  (0) 2021.05.18
Spring 01 : 프로젝트 환경설정  (0) 2021.05.18

API

@GetMapping("hello-string") 
	@ResponseBody 
	public String helloString(@RequestParam("name") String name){
		return "hello " + name; 
	}
  • ResponseBody : http의 body부분에 데이터를 직접 넣어주겠다. view사용X
  • RequestParam : HttpServletRequest 객체와 같은 역할.

 

비즈니스 요구사항

  • 컨트롤러 : 웹 MVC의 컨트롤러 역할
  • 서비스 : 핵심 비즈니스 로직 구현 (비즈니스적인 용어 사용_join)
  • 리포지토리 : 데이터베이스에 접근, 도메인 객체를 DB에 저장하고 관리 (개발적인 용어 사용_save)
  • 도메인 : 비즈니스 도메인 객체
  • 아직 데이터 저장소가 선정X. 인터페이스로 구현 클래스를 변경할 수 있도록 설계.

 

회원 도메인/리포지토리 생성

  • 회원 객체(VO) 생성
  • 회원 리포지토리 인터페이스 생성
  • 회원 리포지토리 메모리 구현

 

회원 리포지토리 테스트 케이스 작성

  • JUnit이라는 프레임워크로 테스트
  • 동작하는지 보기위해 테스트케이스 작성
  • 테스트는 서로 의존관계가 없어야한다. 순서 상관없이 테스트가 되어야한다.

TDD(테스트주도개발) : 테스트를 먼저 만들고 구현 클래스를 만들어 돌려보는 것

 

 

회원 리포지토리 메모리 구현체 테스트

@AfterEach
public void afterEach(){
	repository.clearStore();
}
  • @AfterEach : 여러 테스트를 한꺼번에 실행 시, 메모리 DB에 직전 테스트의 결과가 남을 수 있다. @AfterEach 를 사용하여 각 테스트가 종료될 때 마다 메모리 DB에 저장된 데이터를 삭제한다.


회원 서비스 개발

private void validateDuplicateMember(Member member) {
	memberRepository.findByName(member.getName())
    .ifPresent(m -> {
    	throw new IllegalStateException("이미 존재하는 회원입니다.");
    });
 }
  • 람다 표현식
  • 인터페이스가 갖고 있는 메소드를 간편하게 즉흥적으로 구현해서 사용하는 것이 목적
  • (매개변수목록) -> { 함수몸체 }


회원서비스테스트

void 회원가입() {

	//given
    Member member = new Member();
    member.setName("hello");

	//when
    Long saveId = memberService.join(member);

    //then
    Member findMember = memberService.findOne(saveId).get();
    assertThat(member.getName()).isEqualTo(findMember.getName());
 }
  • 테스트코드는 한글 적어도 괜찮다.
  • given : 이런 상황이 주어져서 (이 데이터를 기반) then : 결과가 이렇게 나와야해
  • when : 이걸로 실행했을 때 (이걸 검증)
@BeforeEachpublic
void beforeEach() {
	memberRepository = new MemoryMemberRepository();
	memberService = new MemberService(memberRepository);
}
  • @BeforeEach : 각 테스트 실행 전에 호출. 테스트가 서로 영향이 없도록 항상 새로운 객체를 생성하고, 의존관계도 새로 맺어준다.


단축키(Windows)

ctrl+alt+v : 변수 선언할 때 사용
alt+enter : static import
ctrl +shift +t : 테스트코드 단축키
shift+f6 : 변수명 바꾸기
ctrl + shift + enter : 완료 후 줄바꿈

인프런 '스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술' 통해 학습 중.

'JAVA' 카테고리의 다른 글

Spring 핵심 01 : 객체 지향 설계와 스프링  (0) 2021.05.18
Spring 05 : AOP  (0) 2021.05.18
Spring 04 : 스프링 DB 접근  (0) 2021.05.18
Spring 03 : 스프링 빈과 의존관계  (0) 2021.05.18
Spring 01 : 프로젝트 환경설정  (0) 2021.05.18

Spring : 자바 플랫폼을 위한 오픈 소스 애플리케이션 프레임워크


Spring 환경설정

  • Java 11
  • IntelliJ

 

스프링 부트 생성

start.spring.io

  • Artifact : 결과물
  • Dependencies : 어떤 라이브러리를 가져다 쓸 것인지?

 

IntelliJ 프로젝트 생성

 

build.gradle 파일

  • maven / gradle 둘 다 main과 test 존재
  • test : test코드 (요즘 개발에서 test코드 매우 중요)

SpringBootApplication : 톰캣 내장함.

 

View 환경설정

  • resources/static/index.html
  • resources/templates/hello.html

 

Controller 설정

  • main/java/hello.hellospring/controller/HelloController.java

 

빌드 후 실행

gradlew.bat build cd build/libs java -jar hello-spring-0.0.1-SNAPSHOT.jar

  • mac에서는 ./gradlew build
  • 서버 배포 시 hello-spring-0.0.1-SNAPSHOT.jar 파일만 복사해서 넣고 java -jar hello-spring-0.0.1-SNAPSHOT.jar 실행. 이렇게 하면 서버에서도 스프링 동작 가능하다.

에러 2개 발생

1) 실행 시 에러

  • gradle을 통해서 실행됨에 따라 에러가 발생
  • 셋팅에서 바꿔줌.

 

2) 실행 후 localhost:8080 들어가면 에러페이지 떠야함.

  • 로그인 창이 뜸.
  • 오라클 DB와 톰캣이 충돌했을 때 나타나는 현상.
  • 오라클 관리자 사이트의 포트를 변경해야 함.

 

변경 후

 

인프런 '스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술' 통해 학습 중.

'JAVA' 카테고리의 다른 글

Spring 핵심 01 : 객체 지향 설계와 스프링  (0) 2021.05.18
Spring 05 : AOP  (0) 2021.05.18
Spring 04 : 스프링 DB 접근  (0) 2021.05.18
Spring 03 : 스프링 빈과 의존관계  (0) 2021.05.18
Spring02 : 예제(회원관리)  (0) 2021.05.18

+ Recent posts