SPRING Core 모듈
- Spring core 모듈은 스프링 프레임워크의 기본적인 기능을 담당하는 모듈 중 하나
- IoC (Inversion of Control) 컨테이너와 DI (Dependency Injection) 컨테이너를 제공
- 객체지향 프로그래밍에서 프로그램 구조를 변경하는 디자인 패턴 중 하나
일반적으로 객체 간의 의존성을 줄이고 결합도를 느슨하게 만들기 위해 사용
스프링 코어의 주요 기능
1. IoC (Inversion of Control) 컨테이너
- 제어의 역전
- 객체 생성과 관리를 담당
- 빈(Bean) 객체들을 생성하고, 의존성 주입(DI)을 수행
- 빈의 생명주기를 관리
- XML, 애노테이션, 자바 설정 파일을 사용하여 빈의 구성을 정의
→ 개발자는 객체를 사용하기 위해 필요한 인터페이스를 정의하는 것에 집중할 수 있음
2. DI (Dependency Injection) 컨테이너
- 의존성 주입
- 빈(Bean) 객체간의 의존성을 관리
- 런타임 시에 빈들의 의존성을 주입
- 인터페이스와 구현체 간의 결합도를 낮출 수 있음
- 생성자 주입(Constructor Injection), Setter 주입(Setter Injection) 등 다양한 방법을 제공
3. AOP (Aspect Oriented Programming)
- Aspect-Oriented Programming을 지원
- 메서드 호출 전/후 등 특정 시점에서 공통적인 로직을 수행할 수 있도록 함
- 애노테이션을 활용하여 AOP 구현을 간편하게 할 수 있음
4. 유틸리티 클래스 및 기능
- 스프링 프레임워크에서 자주 사용되는 유틸리티 클래스들을 제공
- 프로퍼티 파일을 읽어들이는 등의 기능을 지원
의존성 주입 방법
1. 필드 주입 (Field Injection)
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepository;
// ...
}
2. 수정자 주입 (Setter Injection)
public class UserServiceImpl implements UserService {
private UserRepository userRepository;
@Autowired public
void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
// ...
}
3. 생성자 주입 (Constructor Injection)
public class UserServiceImpl implements UserService {
private final UserRepository userRepository;
@Autowired
public UserServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
// ...
}
- 생성자 주입은 객체 생성 시점에 필요한 의존성을 완전히 제공하고, 불변성을 유지하며, 의존성 변경에 유연하게 대처할 수 있도록 해주므로, 스프링에서도 생성자 주입 방식을 권장
- NullPointerException과 같은 문제를 예방
- 의존성이 변경되는 경우에도 다른 의존성을 받는 생성자를 추가하거나, 기존의 생성자를 수정
- 생성자 주입을 사용하면 불변성(immutability)을 유지하는 클래스를 구현
Spring Core 모듈 주요 아노테이션
Annotation | 설명 | |
@Component | - 스프링의 컴포넌트 스캔 기능을 사용하여 빈으로 등록하고자 하는 클래스에 사용 - 객체생성 제어권을 스프링에게 넘김 (IoC) |
|
@Autowired | 스프링 컨테이너가 해당 타입에 맞는 빈을 자동으로 주입 | |
@Qualifier | 여러 개의 빈이 등록되어 있을 때, 어떤 빈을 주입할지 선택 | |
@Controller | 스프링 MVC에서 컨트롤러 역할을 하는 클래스에 사용 | |
@Repository | 데이터베이스와 관련된 작업을 처리하는 DAO 클래스에 사용 | |
@Service | 비즈니스 로직을 처리하는 서비스 클래스에 사용 | |
@Configuration | 자바 기반의 스프링 설정 클래스에 사용 | |
@Bean | @Configuration 클래스에서 스프링 빈을 직접 등록하기 위한 아노테이션 | |
@Scope | 빈의 범위를 지정하기 위한 아노테이션 | singleton, prototype, request, session, global session 등 |
@Value | - 프로퍼티 값을 주입하기 위한 아노테이션 - 스프링의 PropertyPlaceholderConfigurer를 통해 값을 가져옴 |
// 스프링 설정파일
@Configuration
// 패키지 내부에 있는 @Component 붙은 객체들을 관리하겠다.
@ComponentScan(basePackages = "com.study.springstudy.core")
public class HotelConfig {
}
** @Component(”www”) 별칭 지정, @Qualifier 사용 예시
lombok 롬복 라이브러리
- 자바에서 데이터 클래스를 만들 때마다 항상 반복하는 코드(생성자, getter, setter 등)를
작성한 필드 기반으로 생성해주는 라이브러리 - 자바17버전 이후부터는 레코드 클래스, 그 이전 버전은 롬복 라이브러리를 사용
- @Setter, @Getter, @ToString 등 어노테이션을 클래스 위에 선언하여 사용
@Setter @Getter @ToString @EqualsAndHashCode
@NoArgsConstructor : 기본생성자
@AllArgsConstructor : 모든 필드 초기화 생성자
@RequiredArgsConstructor : 필수 파라미터(final 필드) 초기화 생성자
JDBC Template
Spring Framework에서는 JdbcTemplate 이라는 객체를 제공하여 JDBC의 장점을 유지하면서,
간결한 형태의 API 사용법과 새로운 기능을 제공하여 더욱 편리함
JdbcTemplate을 사용하기 위해서는 먼저 의존성을 추가
더보기
// Maven pom.xml
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.9</version>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>4.1.0</version>
</dependency>
// Gradle build.grale
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
}
// application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/mydatabase
spring.datasource.username=myuser
spring.datasource.password=mypassword <--- 각자 설정에 맞는 값을 입력
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
// application.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydatabase
username: myuser
password: mypassword
driver-class-name: com.mysql.cj.jdbc.Driver
삽입 · 갱신 · 삭제 INSERT, UPDATE, DELETE
- pstmt.updateQuery
- String sql 구문 ?의 값을 파라미터에 추가하면 pstmt.setType(...) 과 같은 효과
- update() 메서드의 인자로는 SQL 쿼리와 바인딩할 매개변수를 전달
- 반환값은 영향을 받은 행의 개수
int update(String sql)
int update(String sql, Object... args)
조회 SELECT
- pstmt.executeQuery
- String sql 구문 ?의 값을 파라미터에 추가할 때 sql, RowMapper, ?값 순서로 파라미터를 사용
- RowMapper 인터페이스를 매핑 시 내가 만든 클래스나 new Int[] 등 배열도 매핑 가능
int query(String spl, RowMapper, ?값...)
int queryForObject(String sql, RowMapper)
int queryForObject(String sql, RowMapper, ?값...)
query()
- 여러 건의 결과를 받아올 수 있음
- 각 행(row)마다 객체로 매핑(mapping)할 수 있도록 RowMapper 인터페이스를 사용
- 이때 "여러 건"의 결과를 받아오므로 해당 메서드의 결과는 List 자료형
- RowMapper는 ResultSet의 각 행(row)을 객체로 변환해주는 콜백(callback) 메서드인 mapRow()를 구현한 인터페이스입니다. 이 인터페이스를 구현하여 ResultSet에서 가져온 데이터를 객체로 변환하고, 변환된 객체를 List 형태로 반환
queryForObject()
- queryForObject 메서드는 단 한 개의 결과만 가져올 수 있음
만약 결과가 여러 개인 sql을 작성하면 에러 발생 - 선언한 클래스 타입으로 반환받고 싶다면 RowMapper를 사용
- RowMapper 인터페이스를 기반으로 클래스를 만들고 해당 클래스에서 mapRow 메서드를 작성
이때 mapRow 메서드의 rs는 ResultSet 객체, rowNum은 결과로 받은 sql 행의 개수
// 익명함수
@Override
public List<Board> findAll() {
String sql = "select * from tbl_board";
return template.query(sql, new RowMapper<Board>() {
@Override
public Board mapRow(ResultSet rs, int rowNum) throws SQLException {
return new Board(rs);
}
});
}
// 람다
@Override
public List<Board> findAll() {
String sql = "select * from tbl_board";
return template.query(sql, (rs, rowNum) -> new Board(rs));
}
내부클래스 예시
더보기
// SELECT : 다중행 조회
public List<Person> findAll() {
String sql = "select * from tbl_person";
List<Person> people = template.query(sql, new PersonMapper());
return null;
}
// 내부 클래스
public static class PersonMapper implements RowMapper<Person> {
@Override
public Person mapRow(ResultSet rs, int rowNum) throws SQLException {
Person p = new Person(
rs.getLong("id"),
rs.getString("person_name"),
rs.getInt("person_age")
);
return p;
}
}