DispatcherServlet

기본적으로 서블릿은 입력, 처리, 출력 순서로 되어있다.
공통적으로 처리해야할 입력부분을 제거해주는 것이 DispatcherServlet의 역할이다.
즉, DispatcherServlet은 전처리를 해주는 역할을 한다.
각 서블릿이나 컨트롤러가 처리해야하는 부분을 DispatcherServlet이 처리를 해주는 것이다.

'Java, Spring > 개념정리' 카테고리의 다른 글

스프링 프레임워크(Spring Framework)  (0) 2023.01.17
Spring JDBC 개요  (0) 2023.01.14
AOP(Aspect Oriented Programming)  (0) 2023.01.12
DI Container  (0) 2023.01.12
DI(Dependency Injection)  (0) 2023.01.12

Spring Framework

Java 엔터프라이즈 개발을 편하게 해주는 오픈소스 경량급 애플리케이션 프레임워크이다.

  • 애플리케이션 프레임워크 : 특정 계층이나 기술, 업무 분야에 국한되지 않고, 애플리케이션의 전 영역을 포괄하는 범용적인 프레임워크를 말한다.
  • 경량급 프레임워크 : 단순한 웹컨테이너에서도 엔터프라이즈 개발의 고급기술을 대부분 사용할 수 있다.
  • 엔터프라이즈 개발 용이 : 개발자가 복잡하고 실수하기 쉬운 Low Level 에 많이 신경 쓰지 않으면서 Business Logic 개발에 전념할 수 있도록 해준다.
  • 오픈 소스 : Spring 은 OpenSource 의 장점을 충분히 취하면서 동시에 OpenSource 제품의 단점과 한계를 잘 극복한다.

Spring Framework 전략

Spring 삼각형

엔터프라이즈 개발의 복잡함을 상대하는 Spring 의 전략 → PSA, AOP, DI, POJO

  1. PSA(Portable Service Abstraction, 서비스 추상화)
    트랜잭션 추상화, OXM(Object XML Mapping) 추상화, 데이터 액세스의 Exception 변환기능 등 기술적인 복잡함은 추상화를 통해 Low Level 의 기술 구현 부분과 기술을 사용하는 개발자는 분리된 인터페이스만 보고 개발하도록 인터페이스로 분리한다.
  2. 객체지향과 DI(Dependency Injection, 의존관계주입)
    Spring 은 객체지향에 충실한 설계가 가능하도록 단순한 객체형태로 개발할 수 있고, DI 는 유연하게 확장 가능한 객체를 만들어 두고, 그 관계는 외부(컨테이너)에서 다이나믹(동적)하게 설정해준다.
  3. AOP(Aspect Oriented Programming, 관점지향프로그래밍)
    AOP 는 애플리케이션 로직을 담당하는 코드에 남아있는 기술 관련 코드를 분리해서, 별도의 모듈로 관리하게 해주는 강력한 기술이다.
  4. POJO(Plain Old Java Object, 일반 자바 객체)
    POJO 는 객체 지향 원리에 충실하면서, 특정 환경이나 규약에 종속되지 않고 필요에 따라 재활용될 수 있는 방식으로 설계된 객체이다.

Spring Framework 의 특징

  1. 컨테이너 역할
    Spring 컨테이너는 Java 객체의 LifeCycle 을 관리하며, Spring 컨테이너로 부터 필요한 객체를 가져와 사용할 수 있다.
  2. DI(Dependency Injection) 지원
    Spring 은 설정 파일이나 어노테이션을 통해서 객체 간의 의존관계를 설정할 수 있도록 한다.
  3. AOP(Aspect Oriented Programming) 지원
    Spring 은 트랜잭션이나 로깅, 보안과 같이 공통적으로 필요로 하는 모듈들을 실제 핵심 모듈에서 분리하여 적용할 수 있다.
  4. POJO(Plain Old Java Object)
    Spring 컨테이너에 저장되는 Java 객체는 특정한 인터페이스를 구현하거나, 특정 클래스를 상속 받지 않아도 된다.
  5. 트랜잭션 처리를 위한 일관된 방법을 지원
    JDBC, JPA 등 어떤 트랜잭션을 사용하건 설정(XML, annotation)을 통해 정보를 관리하므로, 트랜잭션 구현에 상관없이 동일한 코드로 사용가능하다.
  6. 영속성(Persistence)과 관련된 다양한 API 지원
    Spring 은 MyBatis, Hibernate 등 데이터베이스 처리를 위한 ORM(Object Relation Mapping) 프레임워크들과의 연동 지원

Spring Framework 를 구성하는 기능 요소

  • Spring Core
    • Spring Framework 의 기본기능(컨테이너)을 제공한다.
    • 이 모듈에 있는 BeanFactory 는 Spring 의 기본 컨테이너면서 Spring DI 기반이다.
  • Spring AOP
    • AOP 모듈을 통해 Aspect 지향 프로그래밍(공통 로직 분리)을 지원한다.
    • AOP 모듈은 스프링 애플리케이션에서 Aspect 를 개발할 수 있는 기반을 지원한다.
  • Spring ORM
    • MyBatis, Hibernate, JPA 등 널리 사용되는 ORM 프레임워크와의 연결고리를 제공한다.
    • ORM 제품들을 Spring 의 기능과 조합해서 사용할 수 있도록 해준다.
  • Spring DAO
    • JDBC 에 대한 추상화 계층으로 JDBC 코딩이나 예외처리 하는 부분을 간편화 시켰으며, AOP 모듈을 이용해 트랜잭션 관리 서비스도 제공한다.
  • Spring Web
    • 일반적인 웹 애플리케이션 개발에 필요한 기본 기능을 제공한다.
    • Webwork 나 Struts 와 같은 다른 웹 애플리케이션 프레임워크와의 통합을 지원한다.
  • Spring Context
    • Context 모듈은 Spring Core 의 BeanFactory 개념을 확장한 것으로, 국제화(I18N) 메시지, 애플리케이션 생명주기, 이벤트, 유효성 검증 등을 지원한다.
  • Spring Web MVC
    • MVC 란 Model, View, Controller 를 의미하며, Spring Web MVC 는 사용자의 인터페이스가 애플리케이션 로직과 분리되는 웹 애플리케이션을 만드는 경우에 일반적으로 사용되는 패러다임이다.

'Java, Spring > 개념정리' 카테고리의 다른 글

DispatcherServlet  (0) 2023.02.02
Spring JDBC 개요  (0) 2023.01.14
AOP(Aspect Oriented Programming)  (0) 2023.01.12
DI Container  (0) 2023.01.12
DI(Dependency Injection)  (0) 2023.01.12

DAO(Data Acess Object) 패턴

  • 데이터 액세스 계층은 DAO 패턴을 적용하여 비즈니스 로직과 데이터 액세스 로직을 분리하는 것이 원칙이다.
  • 비즈니스 로직이 없거나 단순하면 DAO 와 서비스 계층을 통합 할 수도 있지만, 의미있는 비즈니스 로직을 가진 엔터프라이즈 애플리케이션이라면 데이터 엑세스 계층을 DAO 패턴으로 분리해야 한다.
  • DAO 패턴은 서비스 계층에 영향을 주지 않고 데이터 액세스 기술을 변경할 수 있는 장점을 가지고 있다.

Connection Pooling을 지원하는 DataSource

Connection Pooling은 미리 정해진 개수만큼의 DB Connection 을 Pool 에 준비해두고, 애플리케이션이 요청할 때마다 Pool 에서 꺼내서 하나씩 할당해주고, 다시 돌려받아서 Pool 에 넣는 식의 기법이다.

  • 다중 사용자를 갖는 엔터프라이즈 시스템에서라면 반드시 DB Connection Pooling 기능을 지원하는 DataSource 를 사용해야 한다.
  • Spring 에서는 DataSource 를 공유가능한 Spring Bean 으로 등록해주어 사용할 수 있도록 해준다.

DataSoucre 구현 클래스 종류

  1. 테스트 환경을 위한 DataSource
    • SimpleDriverDataSource
      • Spring 이 제공하는 가장 단순한 DataSource 구현 클래스
      • getConnection() 을 호출할 때 마다, 매번 DB Connection 을 새로 만들고, 따로 pool 을 관리하지 않으므로, 단순한 테스트용으로만 사용해야한다.
    • SingleConnectionDriverDataSource
      • 순차적으로 진행되는 통합 테스트에서는 사용 가능하다.
      • 매번 DB Connection 을 생성하지 않기 때문에, SimpleDriverDataSource 보다 빠르게 동작한다.
  2. 오픈소스 DataSource
    • Apache Commons DBCP
    • c3p0 JDBC / DataSource Resource Pool]
    • 두 가지 모두 setter 메서드를 제공하므로 Spring Bean 으로 등록해서 사용하기 편리하다.

Spring JDBC

JDBC 는 모든 자바의 데이터 액세스 기술의 근간이 된다. Entity Class 와 annotation 을 이용하는 최신 ORM 기술도 내부적으로는 DB 와의 연동을 위해 JDBC 를 이용한다.

  • 안정적이고 유연한 기술이지만, low level 기술로 인식되고 있다.
  • 간단한 SQL 을 실행하는 데도 중복된 코드가 반복적으로 사용되며, DB 에 따라 일관성 없는 정보를 가진 채로 Checked Exception 으로 처리한다.
장점 단점
대부분의 개발자가 잘 알고 있는 친숙한 데이터 액세스 기술로, 별도의 학습 없이 개발이 가능하다. Connection 과 같은 공유 리소스를 제대로 릴리즈 해주지 않으면 시스템의 자원이 바닥나는 버그를 발생시킨다.

Spring JDBC 는 JDBC 의 장점과 단순성을 그대로 유지하면서도 기존 JDBC 의 단점을 극복할 수 있게 해주고, 간결한 형태의 API 사용법을 제공하며, JDBC API 에서 지원되지 않는 편리한 기능을 제공한다.

  • Spring JDBC 는 반복적으로 해야 하는 많은 작업들을 대신 해준다.
  • Spring JDBC 를 사용할 때는 실행할 SQL 과 바인딩 할 파라미터를 넘겨주거나, 쿼리의 실행 결과를 어떤 객체에 넘겨 받을지를 지정하는 것만 하면 된다.
  • Spring JDBC 를 사용하려면 먼저, DB Connection 을 가져오는 DataSource 를 Bean 으로 등록해야한다.

Spring JDBC 가 해주는 작업

  1. Connection 열기와 닫기
    • Connection 과 관련된 모든 작업을 Spring JDBC 가 필요한 시점에서 알아서 진행한다.
    • 진행 중에 예외가 발생했을 때도 열린 모든 Connection 객체를 닫아준다.
  2. Statement 준비와 닫기
    • SQL 정보가 담긴 Statement 또는 PreparedStatement 를 생성하고, 필요한 준비 작업을 해주는 것도 Spring JDBC가 한다.
    • Statement 도 Connection 과 마찬가지로 사용이 끝나고 나면 Spring JDBC 가 알아서 객체를 닫아준다.
  3. Statement 실행
    • SQL 담긴 Statement 를 실행하는 것도 Spring JDBC 가 해준다.
    • Statement 의 실행결과는 다양한 형태로 가져올 수 있다.
  4. ResultSet Loop 처리
    • ResultSet 에 담긴 쿼리 실행 결과가 한 건 이상이면 ResultSet Loop 를 만들어서 반복해주는 것도 Spring JDBC 가 해주는 작업이다.
  5. Exception 처리와 반환
    • JDBC 작업 중 발생하는 모든 예외는 Spring JDBC 예외 변환기가 처리한다.
    • 체크 예외(Checked Exception)인 SQLException 을 런타임 에외(Runtime Exception)인 DataAccessException 타입으로 변환한다.
  6. Transaction 처리
    • Spring JDBC 를 사용하면 transaction 과 관련된 모든 작업에 대해서는 신경 쓰지 않아도 된다. (ex. commit, rollback)

JdbcTemplate 클래스

Spring JDBC 가 제공하는 클래스 중 JdbcTemplate 은 JDBC 의 모든 기능을 최대한 활용할 수 있는 유연성을 제공하는 클래스이다.

  • JdbcTemplate 이 제공하는 기능은 실행, 조회, 배치의 세가지 작업이다.
    • 실행 : Insert 나 Update 같이 DB 의 데이터에 변경이 일어나는 쿼리를 수행하는 작업
    • 조회 : Select 를 이용해 데이터를 조회하는 작업
    • 배치 : 여러 개의 쿼리를 한 번에 수행해야 하는 작업

JdbcTemplate 클래스 생성

  • JdbcTemplate 은 DataSource 를 파라미터로 받아서 아래와 같이 생성할 수 있다.
JdbcTemplate template = new JdbcTemplate(dataSoucrce);
  • DataSource 는 보통 Bean 으로 등록해서 사용하므로 JdbcTemplate 이 필요한 DAO 클래스에서 DataSource Bean 을 DI 받아서 JdbcTemplate 을 생성할 때 인자로 넘겨주면 된다.
  • JdbcTemplate 은 멀티스레드 환경에서도 안전하게 공유해서 쓸 수 있기 때문에 DAO 클래스의 인스턴스 변수에 저장해 두고 사용할 수 있다.

JdbcTemplate 클래스 생성 Code

  • 아래의 코드는 일반적으로 사용되는 DAO 클래스의 기본 구조이다. DataSource 에 대한 수정자 메서드에서 직접 JdbcTemplate 객체를 생성해준다.
public class UserDAOJdbc {
  JdbcTemplate jdbcTemplate;

  @Autowired
  public void setDataSource(Datasource dataSource) {
    jdbcTemplate = new JdbcTemplate(dataSource);
  }
}

JdbcTemplate 클래스의 update() 메서드

  • INSERT, UPDATE, DELETE 와 같은 SQL 을 실행할 때는 JdbcTemplate 의 update() 메서드를 사용한다.
int update(String sql, [SQL 파라미터])
  • update() 메서드를 호출할 때는 SQL 과 함께 바인딩 할 파라미터는 Object 타입 가변인자 (Object ... args) 를 사용할 수 있다.
  • update() 메서드의 리턴되는 값은 SQL 실행으로 영향을 받은 레코드의 개수를 리턴한다. (-1, 0, 1 이 성공, 실패의 기준이 되는 이유)

JdbcTemplate 클래스의 update() 메서드 Code

public int update(User user) {
  StringBuffer updateQuery = new StringBuffer();
  updateQuery.append("UPDATE users SET ");
  updateQuery.append("password=?, name=?");
  updateQuery.append("WHERE id=? ");

  int result = this.jdbcTemplate.update(updateQuery.toString(), user.getName(), user.getPassword(), user.getId()); // StringBuffer 로 만든 SQL 문을 toString() 메서드를 이용
  // 각 값들을 get() 메서드를 통해서 얻어온다.

  return result; // 값을 반환
}

JdbcTemplate 클래스의 queryForObject() 메서드

  • SELECT SQL 을 실행하여 하나의 Row 를 가져올 때는 JdbcTemplate 의 queryForObject() 메서드를 사용한다.
    • queryForObject() 메서드는 여러개의 Column, 하나의 Row
    • query() 메서드는 여러개의 Column, 여러개의 Row
<T> T queryForObject(String sql, [SQL 파라미터], RowMapper<T> rm)
  • SQL 실행 결과는 여러 개의 Column 을 가진 하나의 Row
  • T 는 VO(Value Object) 객체의 타입에 해당된다. (T 는 Colum 이 여러개, Row 가 하나일 때 VO 객체의 타입에 해당된다.)
  • SQL 실행 결과로 돌아온 여러 개의 column 을 가진 한 개의 Row 를 RowMapper 콜백을 이용해 VO 객체로 매핑해준다.

JdbcTemplate 클래스의 queryForObject() 메서드 Code

public User findUser (String id) {
  return this.jdbcTemplate.queryForObejct("SELECT * FROM users WHERE id=?", new Object[] {id}),

  new RowMapper<User>() {
    public User mapRow(ResultSet rs, int rowNum) throws SQLException {
      User user = new User();
      user.setId(rs.getString("id"));
      user.setName(rs.getString("name"));
      user.setPassword(rs.getString("password"));

      return user;
        } // RowMapper
      }; // queryForObject
} // findUser

JdbcTemplate 클래스의 query() 메서드

  • SELECT SQL 을 실행하여 여러 개의 Row 를 가져올 때는 JdbcTemplate 의 query() 메서드를 사용한다.
<T> List<T> query(String sql, [SQL 파라미터], RowMapper<T> rm)
  • SQL 실행 결과로 돌아온 여러 개의 column 을 가진 여러 개의 Row 를 RowMapper 콜백을 이용해 VO 객체로 매핑해준다.
  • 결과 값은 매핑한 VO 객체를 포함하고 있는 List 형태로 받는다. (Row 가 여러개이기 때문에) List의 각 요소가 하나의 Row 에 해당한다.

DataSource 설정

  • DataSource 를 Spring Bean 으로 등록하여 사용할 수 있다.

bean.xml

<context:property-placeholder location="classpath:config/value.properties" />

<bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
  <property name= "driverClass" value="${db.driverClass}" />
  <property name= "url" value="${db.url}" />
  <property name= "username" value="${db.username}" />
  <property name= "password" value="${db.password}" />
</bean>

value.properties

db.driverClass=oracle.jdbc.OracleDriver
#mysql, mariadb 의 경우에는 다른 driverClass 와 다른 url 을 사용해야한다.
db.url=jdbc:oracle:thin:@127.0.0.1:1521:orcl
db.username=scott
db.password=tiger

'Java, Spring > 개념정리' 카테고리의 다른 글

DispatcherServlet  (0) 2023.02.02
스프링 프레임워크(Spring Framework)  (0) 2023.01.17
AOP(Aspect Oriented Programming)  (0) 2023.01.12
DI Container  (0) 2023.01.12
DI(Dependency Injection)  (0) 2023.01.12

AOP(Aspect Oriented Programming, 관점 지향 프로그래밍)


- AOP 는 OOP 를 더욱 OOP 답게 만들어 줄 수 있다. - AOP 는 OOP 뿐만 아니라 기존의 절차적 프로그래밍에도 적용될 수 있다.

핵심 관심 모듈은 비즈니스 로직, 횡단 관심 모듈은 비즈니스 로직을 서포트하는 기능적인 요소들을 제공하는 모듈이다.
예를 들어, AOP 를 사용하지 않으면, 계좌이체시에 로깅이라는 작업이 필요하기에, 직접 계좌이체에 메서드를 수정해야하지만, AOP 를 사용하므로써, 위빙(Weaving)을 한다.
위빙은 핵심 관심 모듈과 횡단 관심 모듈을 합치는 것이며, 프레임워크는 이러한 위빙 작업을 통해 핵심 모듈 사이사이에 필요한 횡단 관심 코드가 동작하도록 엮어지게 만든다.

'Java, Spring > 개념정리' 카테고리의 다른 글

스프링 프레임워크(Spring Framework)  (0) 2023.01.17
Spring JDBC 개요  (0) 2023.01.14
DI Container  (0) 2023.01.12
DI(Dependency Injection)  (0) 2023.01.12
DI, IoC, Container  (0) 2023.01.10

Spring DI Container

Spring DI Container 가 관리하는 객체를 빈(Bean) 이라고 하고, 이 빈(Bean)들을 관리하는 의미로 컨테이너를 BeanFactory 라고 부른다.

  • 객체의 생성과 객체 사이의 run-time 관계를 DI 관점에서 볼 때는 컨테이너를 BeanFactory 라고 한다.
  • BeanFactory 에서 여러가지 컨테이너 기능을 추가하여 ApplicationContext 라고 부른다.




BeanFactory 와 ApplicationContext

BeanFactory ApplicationContext
- Bean을 등록, 생성, 조회, 반환 관리함
- 보통 BeanFactory 를 바로 사용하지 않고, 이를 확장한 ApplicationContext 를 주로 사용함
- getBean() 메서드가 정의되어 있음 (Bean 을 조회할 수 있는 메서드)
- Bean을 등록, 생성, 조회, 반환 관리하는 기능은 BeanFactory 와 같음
- Spring 의 각종 부가 서비스를 추가로 제공함
- Spring 이 제공하는 ApplicationContext 여러종류의 구현 클래스가 존재함




BeanFactory 와 ApplicationContext 의 클래스 구조


기본적인 DI Container 역할을 하는 BeanFactory 가 최상위 인터페이스로 존재하며, ApplicationEventPublisher, ListableBeanFactory, MessageSource, RsourceLoader 들을 상속받는 ApplicationContext 인터페이스 존재한다.
궁극적으로 ApplicationContext 가 DI Container 역할을 한다.
ApplicaitonContext 를 상속받아서 구체적으로 구현된 클래스는 StaticApplicationContext, GenerixXmlApplicationContext, WebApplicationContext 등이 있고, WebApplicationContext 를 상속받아서 구현된 XmlWebApplicationContext 도 존재한다.

'Java, Spring > 개념정리' 카테고리의 다른 글

Spring JDBC 개요  (0) 2023.01.14
AOP(Aspect Oriented Programming)  (0) 2023.01.12
DI(Dependency Injection)  (0) 2023.01.12
DI, IoC, Container  (0) 2023.01.10
관심사의 분리, MVC 패턴  (0) 2022.08.21

DI의 개념

각 클래스간의 의존관계를 빈 설정(Bean Definition) 정보를 바탕으로 컨테이너가 자동으로 연결해주는 것을 말한다.

  • 개발자들은 빈 설정파일(XML, annotation)에서 의존관계가 필요하다는 정보를 추가하면 된다.
  • 객체 레퍼런스를 컨테이너로부터 주입 받아서, 실행 시에 동적으로 의존관계가 생성된다.
  • 컨테이너가 흐름의 주체가 되어 애플리케이션 코드에 의존관계를 주입해주는 것이다.

DI의 장점

  • 코드가 단순해진다.
  • 컴포넌트간의 결합도가 제거된다.

DI의 유형

  1. Setter Injection - Setter 메서드를 이용한 의존성 삽입
    • 의존성을 입력받는 setter 메서드를 만들고 이를 통해 의존성을 주입
  2. Constructor Injection - 생성자를 이용한 의존성 삽입
    • 필요한 의존성을 포함하는 클래스의 생성자를 만들고 이를 통해 의존성을 주입한다.
  3. Method Injection - 일반 메서드를 이용한 의존성 삽입
    • 의존성을 입력 받는 일반 메서드를 만들고 이를 통해 의존성을 주입한다.

DI를 이용한 클래스 호출방식

클래스가 구현 클래스를 사용한다고 했을 떄, DI를 이용하면 구현 클래스를 바로 의존하는 것이 아닌, 상위 인터페이스만 사용하게 된다.

구현 클래스에 대한 정보는 XML이나 annotation과 같은 설정 파일에 개발자가 기술해 둔다.

그렇게 되면 프레임워크(컨테이너)가 설정 파일을 읽은 뒤에 구현 객체를 생성 후, 의존 관계가 있다는 걸 설정한다.

Setter Injection

Hello.java

package bean;

import java.util.LIst;

public class Hello {
    String name;
    Printer printer;

    public Hello() {}

    public void setName(String name) { this.name = name; }
    public void setPrinter(Printer printer) { this.printer = printer; }
}

Hello 가 StringPrinter 를 의존하게 되는 것이다. (new String Printer 는 어디에도 존재하지 않음)
멤버변수인 Printer printer 를 상단에 설정해 두고, setter 메서드를 선언해둔다.

beans.xml

<bean id="hello" class="bean.Hello">
    <property name="name", value="Spring"/>
    <property name="printer" ref="printer"/>
</bean>

<bean id="printer" class="bean.StringPrinter"/>
<bean id="consolePrinter" class="bean.Console.Printer"/>

bean.xml 에 의존관계에 대한 설정을 해둔 것이다.
bean 은 스프링이 관리해주는 객체라는 뜻으로 받아들이면 된다.
Hello.java 의 setter 메서드와 mapping 되는 태그가 bean.xml의 property 태그라고 보면 된다.
첫번째 property 는 Spring 의 값(value)를 넣고, 두번째 property 는 타입에 해당하는 객체인 printer 를 넣는다.
객체 printer 의 경우아래에 id=printer class="bean.StringPrinter" 라고 위치를 지정해둔다.
bean 의 Setter Injection 은 한 번에 한 개씩 의존관계를 주입받을 수 있다.

Constructor Injection

Hello.java

package bean;

import java.util.LIst;

public class Hello {
    String name;
    Printer printer;

    public Hello(String name, Printer printer) {
        this.name = name;
        this.printer = printer;
    }
}

Constructor Injection 은 Setter Injection 과 다르게, 한 번에 여러개의 인자를 받을 수 있다.
Hello 클래스 안에, 생성자를 선언한다. 이후에 설정파일에서 그 값을 지정한다.

beans.xml

<bean id="hello" class="bean.Hello">
    <constructor-arg index="0" value="Spring"/>
    <constructor-arg index="1" ref="printer"/>
</bean>

<bean id="printer" class="bean.StringPrinter"/>
<bean id="consolePrinter" class="bean.Console.Printer"/>

bean.xml 에 위의 Hello.java 와의 의존관계에 대한 설정을 해둔 것이다.
첫번째 인자는 constructor-arg 에 index=0 (배열이기 때문에), value 값을 넣고, 두번쨰 인자에는 index=1, 타입에 해당하는 객체 (StringPrinter)를 적어둔다.
위의 Setter Injection 과 동일하게, printer 객체에 대한 정보는 bean id="printer" 에 적어둔 주소를 이용한다.

'Java, Spring > 개념정리' 카테고리의 다른 글

AOP(Aspect Oriented Programming)  (0) 2023.01.12
DI Container  (0) 2023.01.12
DI, IoC, Container  (0) 2023.01.10
관심사의 분리, MVC 패턴  (0) 2022.08.21
액션태그  (0) 2022.08.16

DI (Dependency Injection 의존주입)

객체를 직접 생성(new 연산자)하는 것이 아니라 외부에서 생성된 객체를 주입받아 이용하는 것이다.

 

IoC (Inversion of Control, 제어권의 역전)

메소드나 객체의 생성, 라이프 사이클 관리, 호출작업을 개발자가 직접 하는게 아니라, 프레임워크의 컨테이너가 객체에 대한 제어권을 가지고 있는 것이다. (대부분의 프레임워크에서 IoC를 적용하고 있다.)
IoC는 의존관계 설정 및 라이프 사이클을 해결하기 위한 디자인 패턴이다.

 

IoC Container

기능은 객체에 대한 생명 및 생명주기 관리하는 기능 제공한다.

  • 객체의 생성을 책임지고, 의존성을 관리함
  • POJO의 생성, 초기화, 서비스, 소멸에 대한 권한을 가짐
  • 개발자들이 직접 POJO를 생성할 수 있지만 컨테이너에게 맡김
    컨테이너란 무언가를 담고, 특정 기능을 수행하는 프레임워크가 제공하는 논리적 컨텍스트

 

IoC의 분류

  • IoC
    1. DL (Dependency Injection)
    2. DI (Dependency Lookup)
      • Setter Injection
      • Constructor Injection
      • Method Injection

 

DL과 DI

 

DL (의존성 검색) DI (의존성 주입)
저장소에 저장되어 있는 Bean에 접근하기 위해 컨테이너가 제공하는 API를 이용하여 Bean을 LookUp 하는 것 각 클래스간의 의존관계를 빈 설정 정보를 바탕으로 컨테이너가 자동으로 연결해주는 것

DL 사용시에 컨테이너 종속성이 증가하여, 주로 DI를 사용한다.

'Java, Spring > 개념정리' 카테고리의 다른 글

DI Container  (0) 2023.01.12
DI(Dependency Injection)  (0) 2023.01.12
관심사의 분리, MVC 패턴  (0) 2022.08.21
액션태그  (0) 2022.08.16
디렉티브 태그  (0) 2022.08.15

1. 관심사의 분리 (Separation of Concerns)

[YoilTeller.java]
// 날짜 연월일을 입력하면, 날짜를 말해주는 프로그램
@Controller // Controller 를 통해서, 로컬프로그램을 원격프로그램으로 변경
public class YoilTeller { 
    // public static void main(String[] args) {
        @RequestMapping("/getYoil")
        public void main(HttpServletRequest request, HttpServletResponse response) throws IOException{
        // 1. 입력
        String year = request.getParameter("year");
        String month = request.getParameter("month");
        String day = request.getParameter("day");

        // 2. 작업
        int yyyy = Integer.parseInt(year);
        int mm = Integer.parseInt(month);
        int dd = Integer.parseInt(day);

        Calendar cal = Calendar.getInstance();
        cal.set(yyyy, mm - 1, dd);

        int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK); // 1 = 일, 2 = 월 ...
        char yoil = "일월화수목금토".charAt(dayOfWeek);

        // 3. 출력
        response.setContentType("text/html"); // response 객체 형식을 적어야한다. 즉, 출력할 내용의 타입을 적어야한다.
        response.setCharacterEncoding("UTF-8"); // 텍스트도 인코딩을 해야지 한글이 깨지지 않는다.
        PrintWriter out = response.getWriter(); // response객체에서 브라우져로의 출력 스트림을 얻는다.
        out.println(year + "년" + month + "월" + day + "일은 "); 
        // 원래 제대로 하려면 HTML 형식을 갖춰서 해야한다.
        out.println(yoil + "요일입니다.");
    }
}

관심사는 해야할 작업이라 생각하면 된다.
객체 지향적으로는 코드 분리를 잘해야한다.
현재 위의 [YoilTeller.java]파일에서 main이라는 메소드는 3개의 관심사가 있다.
즉 OOP 5대 설계원칙(SOLID)에 부합하는 코드로 보면, 좋은 코드는 아니다.
(SOLID는 추후에 계속 설명) SOLID의 S는 SRP는 단일 책임 원칙이다.
단일 책임(관심사)의 원칙은 "하나의 메소드는 하나의 책임만 진다"는 뜻이다.
즉 3개의 관심사를 분리해야한다.

분리

  • 관심사의 분리
  • 변하는 것과 변하지 않는 것의 분리 (common, uncommon = 자주 변하는 것과 아닌 것)
  • 공통코드(중복코드)

작성한 코드를 보고, 3가지 분리사항에 부합하는지 보면 객체 지향적으로 잘 분리된 코드로 볼 수 있다.

2. 공통 코드의 분리 - 입력의 분리

각각의 입력부분을 떼어서, 공통코드로 한 곳으로 분류한다.

@RequestingMapping("/getYoil")
public void main(HttpServletRequest request, HttpServletRespons)

String을 int로 쓸 수도 있다.
(YoilTellerMVC.java 참고) 자동변환도 된다.
공통코드를 분리함으로써, 하나의 관심사가 사라지게 된다.

3. 출력(view)의 분리 - 변하는 것과 변하지 않는 것의 분리

[Spring MVC]

사용자의 요청이 들어오게 되면, 앞에서 입력처리를 한다. (DispatcherServlet),
DispatcherServlet 입력 처리 후에 해당 Controller에게 넘겨준다.
Controller는 처리한 결과를 Model 객체를 하나 만든 뒤에 값들을 다 저장하고 DispatcherServlet이 Model을 View에 전달한다.
View는 작업 결과를 읽어서, 응답을 만들어 낸 뒤에, 클라이언트에게 전송하게 된다.
이것이 Spring MVC 패턴이다.

4. MVC 패턴

View를 Controller와 분리하게 되면, 상황에 맞는 View를 보여주기 편리해진다.
그렇기에 아래의 경우에는 yoil.jsp와 yoilError.jsp 로 구분했다.

[YoilTellerMVC.java]
// 날짜 연월일을 입력하면, 날짜를 말해주는 프로그램
@Controller // Controller 를 통해서, 로컬프로그램을 원격프로그램으로 변경
public class YoilTellerMVC { 
        @RequestMapping("/getYoilMVC") // RequestMapping은 중복되는 게 있으면 안된다.
        public String main(int year, int month, int day, Model model) throws IOException{
        // String을 int로 변경, 반환타입은 String으로 변경

            // 1. 유효성 검사 필요
            if(isValid(year, month, day))
                return "yoilError"; // WEB_INF/views/yoilError.jsp = 에러시에 나오는 view

            // 2. 요일 계산
            char yoil = getYoil(year, month, day);

            // 3. 계산한 결과를 Model에 저장
            model.addAttribute("year", year);
            model.addAttribute("month", month);
            model.addAttribute("day", day);
            model.addAttribute("yoil", yoil);

            return "yoil"; // WEB_INF/views/yoil.jsp
    }

        private boolean isValid(int year, int month, int day) {
            // 클래스 내에서만 쓰기에 private
            return true;
        }

        private char getYoil(int year, int month, int day) {
            Calendar cal = Calendar.getInstance();
            cal.set(year, month - 1, day);

            int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK); // 1 = 일, 2 = 월 ...
            return "일월화수목금토".charAt(dayOfWeek);
        }
}
[yoil.jsp]
<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
    <title>yoil</title>
</head>
<body>
<P> ${year }년 ${month }월 ${day }일은 ${yoil }입니다. </P>
</body>
</html>
[yoilError.jsp]
<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
    <title>yoilError</title>
</head>
<body>
<P>  잘못된 요청입니다.<br>
    년, 월, 일을 모두 올바르게 입력해주세요. </P>
</body>
</html>

[servlet-context.xml]

src/main/webapp/WEB-INF/spring/appServlet 에 있는 servlet-context.xml에 적혀있는 것이다.
아래 코드 때문에, 접두사나 접미사에 경로나 확장자가 붙는 것이다.

<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <beans:property name="prefix" value="/WEB-INF/views/" />
        <beans:property name="suffix" value=".jsp" />
</beans:bean>

5. ModelAndView

// 날짜 연월일을 입력하면, 날짜를 말해주는 프로그램
@Controller // Controller 를 통해서, 로컬프로그램을 원격프로그램으로 변경
public class YoilTellerMVC { 
        @RequestMapping("/getYoilMVC") // RequestMapping은 중복되는 게 있으면 안된다.
        public ModelAndView main(int year, int month, int day) throws IOException{
            // 반환타입을 ModelAndView로 변경
            // 1. model and view의 경우
            ModelAndView mv = new ModelAndView();

            // 2. 유효성 검사
             if(!isValid(year, month, day))
                 return mv;

            // 3. 작업
            char yoil = getYoil(year, month, day);

            // 4. 작업 결과를 ModelAndView에 저장
            mv.addObject("year", year);
            mv.addObject("month", month);
            mv.addObject("day", day);
            mv.addObject("yoil", yoil);

            // 5. 결과를 보여줄 view를 지정
            mv.setViewName("yoil"); // view의 이름을 지정 // WEB_INF/views/yoil.jsp
            return mv;
    }
}

6. 컨트롤러 메서드의 반환타입

  • [String]인 경우 = 뷰 이름을 반환
  • [void]인 경우 = 맵핑된 url의 끝 단어가 뷰 이름
  • [ModelAndView]인 경우 = Model과 뷰 이름을 반환

'Java, Spring > 개념정리' 카테고리의 다른 글

DI(Dependency Injection)  (0) 2023.01.12
DI, IoC, Container  (0) 2023.01.10
액션태그  (0) 2022.08.16
디렉티브 태그  (0) 2022.08.15
스크립트태그  (0) 2022.08.15

+ Recent posts