스프링 시큐리티의 모듈 구성

  스프링 시큐리티는 컴포넌트 역할에 따라 모듈이 분리되어 있으며 일반적인 웹 애플리케이션에 보안 기능을 갖출 때

  필요한 모듈은 다음 4가지이다.

모듈명

설명

spring-security-core

인증과 인가 기능을 구현하기 위한 핵심적인 컴포넌트로 구성

spring-security-web

웹 애플리케이션의 보안 기능을 구현하기 위한 컴포넌트로 구성

spring-security-config

각 모듈에서 제공하는 컴포넌트의 설정을 지원하기 위한 컴포넌트로 구성됨(자바 기반 설정 방식을 지원하는 클래스나 XML 네임스페이스를 해석하는 클래스 등)

spring-security-taglibs

인증 정보나 인가 정보를 사용하기 위한 JSP 태그 라이브러리로 구성됨

 

프레임워크 아키텍처

  서블릿 필터의 메커니즘을 활용해 웹 애플리케이션의 보안 기능을 지원하는 아키텍처를 채택하고 있으며,

  다음과 같은 흐름으로 동작한다.

 

  1. 클라이언트는 웹 애플리케이션에 요청을 보낸다

  2. 스프링 시큐리티의 FilterChainProxy 클래스(서블릿필터)가 요청을 받은 다음, HttpFirewall 인터페이스의 메소드를

     호출해서 HttpServletRequest와 HttpServletResponse에 대한 방화벽 기능을 수행한다.

  3. FilterChainProxy 클래스는 SecurityFilterChain에 설정되어 있는 보안 필터 클래스에 처리를 위임한다.

     이 필터는 실제로 서블릿 필터 형태로 만들어져 있다.

  4. SecurityFilterChain에는 여러 보안 필터가 연쇄적으로 연결된 형태로 설정 되어 있으며, 앞의 보안 필터가 

     정상적으로 처리되면 뒤이은 보안 필터가 뒤이어 호출되는 방식으로 동작한다.

  5. 마지막 보안 필터의 처리가 정상적으로 종료되면 뒤이어 남은 서블릿 필터나 서블릿이 실행되어 웹 애플리케이션의

     리소스에 접근할 수 있게 된다.

  6. FilterChainProxy 클래스는 웹 애플리케이션에서 반환한 리소스를 클라이언트에 전달한다.

 

  프레임워크에서 주요 기능을 처리하는 컴포넌트는 다음과 같다.

 

  FilterChainProxy

    FilterChainProxy 클래스는 프레임워크의 진입점 역할을 하는 서블릿 필터 클래스다.

    이 클래스는 프레임워크에서 처리되는 전체 흐름을 제어하고 보안 기능과 같은 추가 기능을 필터에 위임하는

    방식으로 동작한다.

  

  HttpFirewall

    HttpFirewall 인터페이스는 HttpServletRequest와 HttpServletResponse에 대한 방화벽 기능을 추가하기 위한 

    인터페이스이다. 기본적으로 DefaultHttpFirewall 클래스가 사용되고, 디렉터리 탐색 공격이나 인가되지 않은

    요청을 차단하는 역할을 한다.

 

  SecurityFilterChain

    SecurityFilterChain 인터페이스는 FilterChainProxy가 받은 요청에 적용할 보안 필터 목록을 관리하기 위한 

    인터페이스다. 기본적으로 DefaultSecurityFilterChain 클래스가 사용되고 요청 패턴 별로 보안 필터 목록을

    관리한다.

    예를들어, 다음과 같이 빈을 정의하면 지정한 경로 패턴마다 다른 보안기능을 적용할 수 있다.

 

     자바 기반 설정 방식을 이용한 빈 정의

@EnableWebSecurity
public class WebSecurityConfig{
    @Configuration
    @Order(1)
    public ststic class UiWebSecurityConfig extends WebSecurityConfigurerAdapter{
        @Override
        proteted void configure(HttpSecurity http) throws Exception{
            http.antMatcher(*/ui/**");
            //생략
        }
    }
    
    @Configuration
    @Order(2)
    public static class ApiWebSecurityConfig extends WebSecurity ConfigurerAdapter{
        @Override
        protected void configure(HttpSecurity http) throws Exception{
            http.antMatcher("/api/**");
            //생략
        }
    }
}

 

  xml 기반 설정 방식을 이용한 빈 정의

<sec:http pattern="/ui/**">
  <!-- 생략 -->
</sec:http>

<sec:http pattern="/api/**">
  <!-- 생략 -->
</sec:http>

 

보안 필터

  보안필터는 보안 기능을 제공하는 서블릿 필터 클래스이다. 스프링 시큐리티는 이러한 보안 필터를 체인형태로

  연결해서 웹 애플리케이션에 필요한 보안 기능을 하도록 만들어져 있다.

클래스명

설명

SecurityContextPersistenceFilter

인증 정보를 요청 처리 과정 전반에서 공유할 수 있게 만든다. 기본 구현에서는 HttpSession에 인증 정보를 저장해서 공유하는 방식을 쓴다.

UsernamePasswordAuthenticationFilter

요청 파라미터에서 지정한 사용자명과 패스워드를 사용해 인증을 처리한다. 폼 인증을 수행할 때 사용한다.

LogoutFilter

로그아웃 처리를 한다.

FilterSecurityInterceptor

HTTP요청(HttpServletRequest)의 인가를 처리한다.

ExceptionTranslationFilter

FilterSecurityInterceptor에서 발생한 예외를 처리하고 클라이언트에 반환할 응답을 만든다. 기본적인 구현 방식에서는 인증되지 않은 사용자는 인증을 하도록 유도하고, 이미 인증된 사용자라면 인가 오류가 발생했다는 것을 알려준다.

 

(참고 : 스프링 철저 입문)

'Spring' 카테고리의 다른 글

getRealPath("") 경로 wtpwebapps에서 변경하기  (0) 2020.10.29
The prefix "mvc" for element "mvc:interceptors" is not bound.  (0) 2020.10.21
Spring Security  (0) 2020.07.28
스프링 시큐리티, 설정  (0) 2020.06.07
DI & AOP  (1) 2020.05.11

스프링 시큐리티는 애플리케이션에 보안 기능을 구현할 때 사용하는 프레임워크로서, 주로 서블릿 컨테이너에

배포하는 웹 애플리케이션의 보안 기능을 구현할 때 활용한다.

 

특징

  다양한 옵션을 제공

    기본 구현 클래스의 동작 방식을 커스터마이징 할 수 있는 다양한 옵션을 제공한다.

    그래서 기본 동작 방식이 보안 요구사항에 부합하지 않더라도 옵션 값을 변경하는 방법으로 요구사항을 충족하도록

    설정 할 수 있다.

  

  다양한 확장점을 제공

    동작 방식을 커스터마이징 할 수 있는 다양한 확장점을 사용한다. 그래서 기본 동작 방식이 보안 요구사항에 

    부합하지 않더라도 확장 클래스를 만드는 방법으로 요구사항을 충족할 수 있다.

 

기본적인 보안기능

  기본적인 보안기능으로 인증과 인가라는 두가지 기능이 있다.

  

  인증기능

    애플리케이션 사용자의 정당성을 확인한다.

  

  인가기능

    애플리케이션의 리소스나 처리에 대해 접근을 제어한다.

 

강화된 보안기능

  인증과 인가라는 기본적인 기능 외에도 웹 애플리케이션의 보안을 강화하기 위한 기능을 제공한다.

기능

설명

세션 관리 기능

세션 하이재킹(session hijacking)이나 세션 고정(session fixation) 공격으로부터 사용자를 보호하고, 세션의 라이프사이클(생성, 파기, 타임아웃)을 제어한다.

CSRF방지 기능

크로스 사이트 요청 변조(Cross-Site Request Forgery: CSRF) 공격으로부터 사용자를 보호한다.

브라우저의 보안

기능과의 연계기능

브라우저의 보안기능과 연계해서 브라우저 기능을 악용한 공격에서 사용자를 보호 할 수 있는 보안 헤더를 출력한다.

 

시큐리티 라이브러리의 설정

 

pom.xml 정의

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-config</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-taglibs</artifactId>
</dependency>

 

시큐리티의 빈 정의

  설정 클래스의 작성

package.springbook.config;

import org.springframework.security.config.annotation.web.builders.*;
import org.springframework.security.config.annotation.web.configuration.*;

@EnableWebSecurity	//클래스에 @EnableWebSecurity를 지정하면 스프링 시큐리티가 제공하는 설정 클래스가 임포트되고 스프링 시큐리티를 이용할 때 필요한 컴포넌트의 빈이 자동으로 정의된다.
public class WebSecurityConfig extends WebSecurityConfigurerAdapter { //부모클래스로 WebSecurityConfigurerAdapter클래스를 지정한다. 상속하면 기본적으로 적용되는 빈의 정의를 간단히 커스터마이징 할 수 있다.
    @Override
    public void configure(WebSecurity web){
        web.ignoring().antMatchers("/resources/**");  //보안기능이 필요 없는 리소스(CSS나 자바스크립트)에는 스프링 시큐리티를 적용하지 않는다.
    }
}

 

  이렇게 만든 설정 클래스를 사용해 DI 컨테이너가 만들어지도록 정의

 

  web.xml의 설정 예

<listener>
    <listener-class>
        org.springframework.web.context.ContextLoaderListener
    </listener-class>
</listener>
<context-param>
    <param-name>contextClass</param-name>
    <param-value>
        org.springframework.web.context.support.AnnotationConfigWebApplicationContext
    </param-value>
</context-param>
<context-param>
    <!-- contextConfigLocation에 작성한 설정 클래스를 지정 -->
    <param-name>contextConfigLocation</param-name>
    <param-value>springbook.config.WebSecurityConfig</param-value>
</context-param>

 

xml파일 작성

  XML기반 설정 방식을 사용할 때는 다음과 같은 파일을 작성.

  

  XML파일(security-context.xml)의 작성 예

<?xml version="1.0" encoding="UTF-8"?>
<beans
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:sec="http://www.springframework.org/schema/security"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/security
        http://www.springframework.org/schema/security/spring-security.xsd
">
    <!-- 스프링 시큐리티가 제공하는 XML 네임스페이스를 활성화.
         이 예에서는 sec라는 이름을 할당하고 있다.
         네임스페이스를 이용하면 스프링 시큐리티의 컴포넌트를 빈으로 간단히 정의할 수 있다. -->
         
<sec:http>
<!-- <sec:http>요소를 정의. 정의하면 시큐리티를 이용할 때 필요한 컴포넌트의 빈이 자동으로 정의 -->
    <sec:intercept-url pattern="/**" access="isAuthenticated()" />
    <sec:form-login />
    <!-- 이 예에서는 보안 설정이 제대로 적용되었는지 확인하기 쉽도록 요청되는 모든 경로에 인증을 하도록 만들었다.
         인증방식으로는 폼 기반 인증 기능을 사용 -->
</sec:http>

<sec:authentication-manager />
<!-- <sec:authentication-manager>요소를 정의해 인증용 컴포넌트를 빈으로 정의한다.
     이 요소를 정의하지 않으면 서버를 가동할 때 오류가 발생한다. -->

</beans>

 

보안 기능이 필요없는 리소스(CSS나 자바스크립트)에 대해서는 다음과 같이 빈을 정의해서 스프링 시큐리티가 인증을

하지 않게 만든다. 만약 <sec:http>요소가 여러개 정의되어 있다면 정의한 순서대로 경로 패턴을 매칭하기 때문에

위에서 설정한 <sec:http>요소보다 다음 설정을 순서상 먼저 기술 해야 한다.

 

스프링 시큐리티가 인증하지 않도록 하기위한 빈 정의 예

<!-- 인증이 필요없는 리소스에 대한 경로 패턴을 지정 -->
<sec:http pattern="/resources/**" security="none" />

 

이렇게 만든 XML파일을 사용해 DI컨테이너가 만들어지도록 정의한다.

 

web.xml의 설정 예

<listener>
    <listener-class>
        org.springframework.web.context.ContextLoaderListener
    </listener-class>
</listener>
<context-param>
    <!-- contextConfiglocation에 작성한 XML파일을 지정 -->
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:/META-INF/spring/security-context.xml</param-value>
<context-param>

 

서블릿 필터 설정

  마지막으로 스프링 시큐리티에서 제공하는 서블릿 필터 클래스(FilterrChainProxy)를 서블릿 컨테이너에 등록한다.

 

  web.xml의 설정 예

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>
        org.springframework.web.filter.DelegatingFilterProxy
    </filter-class>
</filter>
<!-- 스프링 프레임워크가 제공하는 DelegatingFilterProxy를 사용해 DI컨테이너에서 관리되는
     빈(FilterChainProxy)을 서블릿 컨테이너에 등록.
     서블릿 필터의 이름으로 DI 컨테이너에서 관리되는 빈의 이름(springSecurityFilterChain)을
     지정한다. -->

<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 스프링 시큐리티를 적용할 URL 패턴을 지정. 이 예에서는 모든 요청에 대해 스프링 시큐리티를 적용-->

 

(참고 : 스프링 철저 입문)

'Spring' 카테고리의 다른 글

getRealPath("") 경로 wtpwebapps에서 변경하기  (0) 2020.10.29
The prefix "mvc" for element "mvc:interceptors" is not bound.  (0) 2020.10.21
Spring Security  (0) 2020.07.28
스프링 시큐리티의 아키텍처  (0) 2020.06.07
DI & AOP  (1) 2020.05.11

DI(Dependency Injection  의존성주입)

  표준을 정의할 수 있고, 정의된 표준을 바탕으로 같은 설계를 하게 해준다.

  보통 엔터프라이즈 어플리케이션을 개발할 때는 하나의 처리를 수행하기 위해 여러개의 컴포넌트를 조합해서

  구현하는 경우가 일반적이다.

  이때 사용되는 컴포넌트에는 '공통으로 사용되는 기능을 따로 분리한 컴포넌트', '데이터베이스에 접근하기 위한

  컴포넌트', '외부 시스템이나 서비스에 접속하기 위한 컴포넌트' 등과 같이 다양한 컴포넌트가 있다.

  

  이처럼 하나의 처리를 구현하기 위해 여러개의 컴포넌트를 통합할 때 의존성 주입이라는 접근 방식이 큰 힘을

  발휘한다. 예를들어, 사용자를 등록하는 클래스를 구현한다고 가정하면, 사용자 등록을 위해 필요한 처리 흐름은

  다음과 같다.

    1. 등록하려는 사용자 계정이 이미 등록되어 있는지 확인한다.

    2. 등록하려는 사용자의 패스워드를 해시(Hash)한다.

    3. 사용자 정보를 저장한다.

  

  이 같은 처리를 구현하는데 필요한 인터페이스는 다음과 같다.

  

  사용자 등록을 처리하는 인터페이스

public interface UserService {
	//사용자 정보를 등록한다.
    void register(User user, String rawPassword);
}

 

  패스워드를 해시화하는 인터페이스

public interface PasswordEncoder {
	//패스워드를 해시화한다.
    String encode(CharSequence rawPassword);
}

 

  사용자 정보를 관리하는 인터페이스

public interface UserRepository {
	//사용자 정보를 저장한다.
    User save(User user);
    //사용자 계정명이 일치하는 사용자 수를 카운트한다.
    int countByUsername(String username);
}

 

  사용자 등록을 처리하는 구현 클래스

public class UserServiceImpl implements UserService {
	private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;
    
    public UserServiceImpl(javax.sql.DataSource dataSource) {
    	//데이터베이스 방식으로 사용자 정보를 관리하는 구현 클래스
        this.userRepository = new JdbcUserRepository(dataSource);
        
        //Bcrypt 알고리즘으로 해시화하는 구현 클래스
        this.passwordEncoder = new BCryptPasswordEncoder();
    }
    
    public void register(User user, String rawPassword) {
    	if(this.userRepository.countByUsername(user.getUsername()) > 0) {
        	//같은 사용자 계정의 사용자가 있다면 예외를 발생시킨다.
            throw new UserAlreadyRegisteredException();
        }
    
    //입력된 원본 패스워드를 해시화 한 후, 사용자 정보로 설정한다.
    user.setPassword(this.passwordEncoder.encode(rawPassword));
    this.userRepository.save(user);
    }
}

 

  위 예제에서는 생성자에서 userRepository와 passwordEncoder를 초기호 ㅏ하기 위해 UserRepository 와

  PasswordEncoder의 구현 클래스를 직접 생성해서 할당한다.

  그래서 UserServiceImpl클래스를 개발하는 단계에서는 의존하는 컴포넌트 클래스가 이미 완성되어 있어야 한다.

  

  이처럼 필요한 컴포넌트를 생성자에서 직접 생성하는 방식은 일단 클래스가 생성되고 나면 이미 생성된

  UserRepository나 PasswordEncoder의 구현 클래스를 교체하는것이 사실상 어려울 수 있다.

  이러한 클래스 간의 관계를 두고 '클래스 간의 결합도가 높다'라고 말한다.

 

  엔터프라이즈 애플리케이션을 개발할 때는 다양한 컴포넌트를 조합하는 것이 일반적이라고 했는데,

  많은 컴포넌트에 의존해야 하는 클래스를 이 같은 방식으로 개발하는것은 상당히 비효율적이다.

  예를들어 의존하는 클래스가 아직 개발중이거나, 미들웨어 벤더가 제공해줘야 하는 클래스가 있는데

  그 벤더의 제품이 완성되지 않았을 수도 있다.

  결국 모든 컴포넌트가 제대로 모양새를 갖추려면 개발의 막바지에 이르러서야 오류없이 조립할 수 있다.

  해결 대안으로는 필요한 컴포넌트가 완성 될 때 까지 임시로 dummy 클래스를 만들어서 대체하는 방법이 있다.

  다만, 언젠가는 제대로 구현해서 교체해야 할 코드이기 때문에 개발규모가 커지면 커질수록 재 작업의 양이 늘어난다.

 

  UserServiceImpl 클래스의 결합도를 낮추려면 우선 생성자 안에서 UserRepository와 passwordEncoder의

  구현 클래스를 직접 생성하는 대신, 생성자의 인수로 받아서 할당하는 방법을 생각해볼 수 있다.

 

  생성자를 활용한 의존 컴포넌트 초기화

public UserServiceImpl(UserRepository userRepository,
						PassworkdEncoder passwordEncoder) {
		
        this.userRepository = userRepository;
        this.passwordEncoder = passwordEncoder;
}

 

  이렇게 하면 UserServiceImpl의 소스코드 안에서 UserRepository와 passwordEncoder의 구현 클래스 정보가 제거되어

  UserServiceImpl의 외부에서 UserRepository와 passwordEncoder의 구현체를 쉽게 변경할 수 있게 된다.

 

  애플리케이션에서 UserService를 사용

UserRepository userRepository = new JdbcUserRepository(dataSource);
PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
UserService userService = new UserServiceImpl(userRepository, passwordEncoder);
//생략

  먄약 JdbcUserRepository와 BCryptPasswordEncoder가 아직 완성되지 않았다면 앞서 생성자 안에서 구현 클래스를

  직접 생성하던 방식과 달리 UserServiceImpl을 변경하지 않고 JdbUserRepository와 BCryptEncoder의 더미클래스를

  임시로 만들어서 대체하면 개발을 중단없이 계속 할 수 있다.

 

  미완성된 클래스를 더미로 대체

UserRepository userRepository = new DummyUserRepository();
passwordEncoder passwordEncoder = new DummyPasswordEncoder();
UserService userService = new UserServiceImpl (userRepository, passwordEncoder);
//생략

  하지만 이 경우에도 UserServiceImpl이 의존하는 각 컴포넌트는 개발자가 직접 생성해서 주입해야 하기 때문에

  변경이 발생하는 경우의 재작업은 불가피하다.

  

  어떤 클래스가 필요로 하는 컴포넌트를 외부에서 생성한 후, 내부에서 사용 가능하게 만들어 주는 것을

  '의존성 주입(DI)한다', 또는 '인젝션(Injection)'한다' 라고 말한다.

  그리고 이러한 의존성 주입을 자동으로 처리하는 기반을 'DI 컨테이너'라고 한다.

 

DI 컨테이너

  스프링 프레임워크가 제공하는 기능 중 가장 중요한 것이 DI컨테이너 기능이다.

  스프링 프레임워크의 DI컨테이너에 UserService, UserRepository, PasswordEncoder의 인터페이스와

  구현 클래스를 알려주고 의존관계를 정의해주면 UserServiceImpl이 생성될 때 UserRepository와

  PasswordEncoder의 구현 클래스가 자동으로 생성되어 주입된다.

  UserService를 사용하고 싶은 애플리케이션은 DI 컨테이너에서 UserService를 꺼내오기만 하면 되고,

  이 때 UserRepository와 PasswordEncoder는 UserService에 이미 조합 된 상태이다.

 

  DI 컨테이너에서 UserService 꺼내기

ApplicationContext context = ...; //스프링 DI컨테이너
UserService userService = context.getean(UserService.class);
//생략

 

  이렇게 DI 컨테이너를 통해 각 컴포넌트의 인스턴스를 생성하고 통합 관리하면서 얻을 수 있는 장점은

  컴포넌트간의 의존성 해결 뿐만이 아니다.

  어떤 컴포넌트는 반드시 단 하나의 인스턴스만 만들어서 재사용 되도록 싱글턴(singleton)객체로 만들어야 하고

  어떤 컴포넌트는 매번 필요할 때마다 새로운 인스턴스를 사용하도록 프로토타입(prototype)객체로 만들어야 한다.

  이러한 인스턴스의 스코프(scope)관리를 DI컨테이너가 대신한다.

  각 인스턴스가 필요로 하는 공통 처리 코드를 외부에서 자동으로 끼워넣는 AOP기능도 DI컨테이너가 대신 해준다.

 

DI 개요

  의존성 주입이라고도 하며 IoC라고 하는 소프트웨어 디자인 패턴 중 하나다.

 

  DI 컨테이너에서 인스턴스를 관리하는 방식에는 다음과 같은 장점이 있다.

    1. 인스턴스의 스코프를 제어할 수 있다.

    2. 인스턴스의 생명 주기를 제어할 수 있다.

    3. AOP 방식으로 공통 기능을 집어넣을 수 있다.

    4. 의존하는 컴포넌트 간의 결합도를 낮춰서 단위 테스트 하기 쉽게 만든다.

  스프링의 공식 문서에서는 DI가 아닌 IoC컨테이너라고 기재하고 있다.

 

ApplicationContext와 빈 정의

  스프링 프레임워크에서는 ApplicationContext가 DI 컨테이너의 역할을 한다.

  

  DI컨테이너에서 인스턴스 꺼내기

ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
//설정클래스(Configuration class)를 인수로 전달하고 DI컨테이너를 생성한다.
//설정클래스는 여러개 정의 할 수도 있다.

UserService userService = context.getBean(UserService.class);
//DI컨테이너에서 UserService 인스턴스를 가져온다.

  여기서 AppConfig 클래스는 DI컨테이너에서 설정파일 역할을 하며, 자바로 작성돼 있어서

  자바 컨피규레이션클래스(Java Configuration Class)라고도 한다.

  그리고 이렇게 자바 컨피규레이션 클래스로 설정하는 방식을 자바 기반 설정방식이라고 하며, 다음과 같은 형태로

  작성한다.

 

  자바기반 설정 방식의 예

@Configuration
public class AppConfig {
	@Bean
	UserRepository userRepository() {
		return new UserRepositoryImpl();
	}
	
	@Bean
	PasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
	}
	
	@Bean
	UserService userService() {
		return new UserServiceImpl(userRepository(), passwordEncoder());
	}
}

 

  그리고 이 설정을 사용하는 애플리케이션과 ApplicationContext의 관계는 다음과 같다.

  @Configuration 과 @Bean 어노테이션을 사용해서 DI컨테이너에 컴포넌트를 등록하면 애플리케이션은

  DI 컨테이너에서 있는 빈(Bean)을 ApplicationContext 인스턴를 통해 가져올 수 있다.

  스프링 프레임워크에서는 DI 컨테이너에 등록하는 컴포넌트를 빈이라고 하고, 이 빈에 대한 설정(Configuration)

  정보를 '빈 정의(Bean Definition)'라고 한다.

  또한 DI컨테이너에서 빈을 찾아오는 행위를 룩업(lookup)이라고 한다.

 

  DI 컨테이너에서 빈 가져오기

UserService userService = context.getBean(UserService.class);
//가져오려는 빈의 타입(Type)을 지정하는 방법이다.
//지정한 타입에 해당하는 빈이 DI 컨테이너에 오직 하나만 있을 때 사용한다.
//스프링프레임워크 3.0 부터 사용할 수 있다.

UserService userService = context.getBean("userService", UserService.class);
//가져오려는 빈의 이름과 타입을 지정하는 방법.
//지정한 타입에 해당하는 빈이 DI컨테이너에 여러개 있을 때 이름으로 구분하기 위해 사용.
//2.5.6버전까지는 반환값이 Object 타입이라서 원하는 빈의 타입으로 형변환 해야 했지만
//3.0.0버전 이후부터는 형변환 하지 않아도 된다.

UserService userService = (UserService) context.getBean("userService");
//가져오려는 빈의 이름을 지정하는 방법이다.
//반환값이 Object타입이라서 원하는 빈의 타입으로 형변환 해야 한다.
//1.0.0버전부터 사용할 수 있다.

 

  빈 설정 방법

  자바 기반 설정 방식이나 XML 기반 설정 방식만 사용해서 빈을 정의할 수도 있지만 대부분의 경우 자바 기반

  설정 방식과 어노테이션 기반 설정 방식을 조합하거나 XML 기반 설정 방식과 어노테이션 기반 설정 방식의

  조합을 많이 사용한다.

 

  ApplicationContext를 생성하는 다양한 방법

ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
//자바 기반의 설정방식으로 AnnotationConfigApplicationContext의 생성자에
//@Configuration 어노테이션이 붙은 클래스를 인수로 전달한다.

ApplicationContext context = new AnnotationConfigApplicationContext("com.example.app");
//어노테이션 개반 설정방식으로 AnnotationConfigApplicationContext의 생성자에
//패키지명을 인수로 전달한다.
//지정된 패키지 이하의 경로에서 컴포넌트를 스캔한다

ApplicationContext contet = 
            new ClassPathXmlApplicationContext("META-INF/spring/applicationContext.xml");
//XML 기반의 설정방식으로 ClassPathXmlApplicationContext의 생성자에 XML파일을 인수로 전달한다.
//경로에 접두어(Prefix)가 생략된 경우에는 클래스패스 안에서 상대경로로 설정파일을 탐색한다.

ApplicationContext context =
            new FileSystemXmlApplicationContext("./spring/applicationContext.xml");
//XML기반의 설정방식으로 FileSystemXmlApplicationContext의 생성자에 XML 파일을 인수로 전달한다.
//경로에 접두어가 생략된 경우에는 JVM의 작업 디렉토리 안에서 상대경로로 설정파일을 탐색한다.

  ApplicationContext는 단독 애플리케이션에서 스프링 프레임워크를 사용하거나 JUnit으로 만든 테스트 케이스 안에서

  스프링 프레임워크를 구동할 때 사용된다.

  웹 애플리케이션에서는 스프링 MVC를 활용하게 되는데, 이때는 웹 환경에 맞게 확장한 WebApplicationContext를

  사용한다.

 

빈 설정

 

+ Recent posts