annotation, bean, configuration

여름빛새·2023년 7월 11일

dev-diary

목록 보기
3/8

1. 들어가기에 앞서

이전 글에서는 스프링 시큐리티의 아키텍쳐에 대해 알아봤습니다.
그런데 소스 코드 설명과 관련해서 몇 가지 부분을 분량 상 부득이하게 생략하게 되었는데요.
이번 글에서는 관련된 내용들을 써보도록 하겠습니다.

1.1. anotation

annotation : 주ː석1, 註釋·注釋
낱말이나 문장의 뜻을 쉽게 풀이하는 것. 또는, 그 글. 순화어는 `풀이'.

annotation의 사전적 의미입니다. Java에서의 쓰임새는 코드를 쉽게 사용할 수 있게 보조하는 기능이라고 볼 수 있겠네요. JDK 1.5부터 제공된 기능이며, JDK 1.6 부터 자바 컴파일러 라이브러리인 Javac에 통합됐다고 합니다.

어노테이션의 기능

annotation은 메타데이터 입니다. 데이터를 처리하기 위한 정보를 기술한 데이터라는 것이죠. 다시 말해, annotation은 application에서 처리하는 데이터가 아니라, 특정 코드가 컴파일과 런타임 과정에서 처리해야 할 과정을 annotation에 의해 주입된 정보에 따라 수행하는 것입니다.

간략하게 세분화 한다면, annotation은 아래와 같은 기능을 수행합니다.

  1. java compiler에 코드 작성 문법 에러를 체크하도록 정보를 제공 합니다.
  2. 소프트웨어 개발툴이 빌드나 배치시 코드를 자동으로 생성할 수 있도록 정보 제공 합니다.
  3. 실행(런타임)시 특정 기능을 실행하도록 정보를 제공 합니다.

소스코드에서 어노테이션은 클래스, 메소드, 변수, 매개 변수 및 패키지에 선언할 수 있습니다. 선언된 객체들은 컴파일러에 의해 생성되는 .class 파일에 포함되며, 이를 통해 읽혀집니다.

여기서 잠깐. meta-data란?

  • '속성정보'라고도 불리는 메타데이터는 '데이터에 관한 구조화된 데이터', '다른 데이터를 설명해 주는 데이터'라고 합니다.
  • annotation 클래스들을 제공하여 이를 기반으로 컴파일 과정에서 코드 생성을 지원해주는 대표적인 라이브러리로서는 lombok이 있습니다.

anotation을 정의하기

어노테이션을 생성 및 사용하는 순서는 다음과 같습니다.

1.어노테이션 객체의 명칭을 설정 합니다.

public @interface annotationName{}
  1. 어노테이션 객체의 내부를 정의합니다.
	public @interface annotationName{
    	String elementName1();
    	int elementName2() default 5;
	}

3.클래스에 어노테이션을 배치합니다. 컴파일/런타임 시 해당 클래스는 어노테이션에 따라 코드를 처리합니다.

	@annotationName
	public class ObjectA {
		...
	}

어때요, 참 쉽죠?

사실 대부분의 어노테이션들은 이미 lombok과 같은 라이브러리에서 지원하고 있으니, 크게 중요하진 않습니다.

1.2. java에서의 bean과 component

bean : 콩. 콩과 식물 중 하나.

놀랍게도 사실 입니다. 왜 이런 이름이 붙었는지 궁금할 수도 있는데, 어디까지나 Java의 창시자인 제임스 고슬링의 발상에서 비롯됐기 때문입니다.
java의 이름은 인도네시아 자바 섬에서 따왔고, bean이란 개념은 바로 java의 특산품인 커피 '콩'에서 따온 것입니다. 자바 프로그램의 구성요소를 커피콩에 비유한 것이죠. java의 패키지 파일 확장자명인 'jar'역시, 커피 콩을 항아리에 담는다는 비유로서 명명된 것 입니다.
그러나 유래가 어쨌든 간에, 일개 프로그래밍 언어의 지칭어로서 엄연한 의미를 지니고 있습니다. Java bean은 아래와 같은 코딩 관례를 지켜 작성된 클래스를 의미합니다.

  • 매개변수가 없는 public 생성자가 있습니다.
  • public getter / setter 메소드가 존재합니다.
  • java.io.Serializable을 구현합니다.

이렇게 말하면 뭔가 복잡해보이겠지만, 사실 굉장히 간단합니다.

	public class Gamer implements java.io.Serializable{
 		private String name;
 		public Gamer(){}
 		public void setName(String name){
  			this.name = name;
 		}
 		public String getName(){
  			return this.name;
 		}
        ...
	}

클래스 내 변수를 getter/setter, 두 번에 걸쳐 생성해야 한다는 점에 이 분을 연상시키면 될 것입니다.

component란?

component : 부품.
하드웨어에서 모듈은 독립된 부품으로 만들어지며, 규격화된 단자를 통해 부품 교체를 용이하게 합니다.

객체지향언어에서 component는 인터페이스를 통해 규격화를 이룹니다.
인터페이스에서 제공하는 메서드 환경을 통해 소프트웨어 개발이 가능케 하며 정보은닉(encapsulation)개념을 수행하게 할 수 있으며, 독립된 모듈로 이루어진 소프트웨어를 이루게 합니다.

2. Spring bean, Spring component

Spring IoC 컨테이너가 관리하는 자바 객체를 스프링 빈(Spring Bean)이라고 부릅니다. 그렇다면, Java Bean과 Spring Bean은 어떻게 다를까요?

2.1. Java에서의 Bean

POJO(Plain Old Java Object)에서는 작업을 제어하기 위해서는 사용자가 직접 객체를 생성하고 조작합니다. 예를 들어 A 객체에서 B 객체에 있는 메소드를 사용하고 싶으면, B 객체를 직접 A 객체 내에서 생성하고 메소드를 호출합니다.

import com.example.MyBean; 

public class Example {
	public static void main(String args[]){
    	MyBean bean = new MyBean();
        bean.SetName("홍진호");
        System.out.println(bean.getName());
    	...
    }
}

public class MyBean {
	String name;
    public String getName(String name);
	public void setName(String name) {
		this.name = name;
    }
}

2.2. Spring에서의 Bean

하지만 제어역전(IoC)이 적용된 경우, 빈 객체의 생성을 특별한 관리 위임 주체에게 맡깁니다. 이 경우, 객체 생성에는 사용자가 관여하지 않고, 다른 주체가 객체의 생명 주기를 컨트롤 합니다.

@Controller
@Scope("request")
public class HomeController {	
    private MyBean myBean;
	private MyAnnotatedBean myAnnotatedBean;
    ...
    
    @Autowired
	public void setMyBean(MyBean myBean) {
		this.myBean = myBean;
	}   
    ...
}

이 경우 사용자는 객체를 직접 생성하지 않고, annotation을 통해 MyBean의 객체 생성을 사용자가 아니라 Spring에서 컨트롤 합니다. 이는 사용자의 제어권을 다른 주체에게 넘기는 과정이며, 이를 IOC(제어의 역전) 라고 합니다.
다시 말해 Spring Bean은 Spring에 의해 제어/관리되는 자바 객체를 지칭합니다.

우리가 알던 기존의 자바 프로그래밍 에서는 클래스를 생성하고 메서드 내부에서 원하는 객체를 직접 생성한 후에 사용했었습니다. 하지만 Spring에서는 직접 생성한 객체가 아니라, Spring에 의하여 관리되는 자바 객체를 사용합니다. 이렇게 Spring에 의하여 생성되고 관리되는 자바 객체를 Bean이라고 합니다.

Spring Framework 에서는 Spring Bean 을 얻기 위하여 ApplicationContext.getBean() 와 같은 메소드를 사용하여 Spring 에서 직접 자바 객체를 얻어서 사용합니다.

스프링 빈의 특징은 다음과 같이 요약할 수 있습니다.

  • Spring bean은 Spring에 의해 제어(관리)되는 객체를 말합니다.
  • 다시 말해, Spring Framework의 container에 의해 인스턴스,구성,관리되는 객체입니다.
  • Spring Bean은 @Configuration, application.xml, application.yml 등에 의해 정의 됩니다.
  • @configuration이나 설정 파일에 의해 정의된 bean은 응용 프로그램에 주입됩니다.
  • 또한, SpringBean은 기본 생성자와 getter/setter가 없더라도 객체를 관리할 수 있습니다.

Spring Component

Spring Framework 내에서는 IoC 컨테이너에 등록된 클래스를 지칭합니다.
다시 말해, Spring Bean 객체가 등록된 클래스들을 뜻합니다.

2.3. bean과 component의 등록

2.3.1.@bean

  • 개발자가 컨트롤이 불가능한 외부 라이브러리들을 Bean으로 등록하고 싶은 경우에 사용 합니다. 메소드 또는 어노테이션 단위에 붙일 수 있습니다.
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
	...
}

2.3.2@component

  • 개발자가 직접 컨트롤이 가능한 클래스(=자체적으로 개발한 클래스)들의 경우에 사용됩니다. 클래스 또는 인터페이스 단위에 붙일 수 있으며, 개발자가 직접 작성한 클래스를 bean 등록하고자 할 경우 사용됩니다.
  • Spring에서 지원하는 @Configuration,@Controller,@Service,@Repository 등 의 어노테이션들은 기본적으로 @Component어노테이션의 기능을 포함하고 있습니다.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component {
	...
}

3. 소스코드

3.1. DTO

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class AuthenticationRequest {
    @Column(name = "email_id")
    private String email_id;
    
    @Column(name = "password")
    private String password;
}

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class AuthenticationResponse {

    @Column(name = "access_token")
    private String accessToken;

    @Column(name = "refresh_token")
    private String refreshToken;
}

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class RegisterRequest {
    @Column(name="email_id")
    private String email_id;
    
    @Column(name="password")
    private String password;
}


@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class RestRequest {
    @Column(name="email_id")
    private String email_id;
        
    @Column(name="password")
    private String password;
}

위 소스 코드들은 SquadMania에서 DTO를 담당하는 모델 클래스들 입니다.
Authentication과 Authorization 과정에서 사용한 DTO 클래스입니다.
컴파일 시점에서 해당 어노테이션이 참조하는 메타 데이터를 받아 해당 객체의 getter/setter, 생성자 등을 생성합니다.
어노테이션 선언 없이 작성한다면, 해당 객체는 getter와 setter, 그리고 생성자를 명시하여 사용해야 하지만 하지만, lombok에서 지원하는 라이브러리를 사용하여 이를 최소화할 수 있습니다.
참고로 해당 클래스들은 엄연히 자바 객체이므로, Spring Bean이 아닙니다.

3.2. ApplicationConfig.java

@Configuration
@RequiredArgsConstructor
public class ApplicationConfig {
    private final UserRepository userRepository;

    @Bean
    public UserDetailsService userDetailService(){
        return username -> userRepository.findByEmail(username)
            .orElseThrow(() -> new UsernameNotFoundException("user not found"));
    }

    @Bean
    public AuthenticationProvider authenticationProvider(){
        DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
        authProvider.setUserDetailsService(userDetailService());
        authProvider.setPasswordEncoder(passwordEncoder());
        return authProvider;
    }

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception{
        return config.getAuthenticationManager();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

}

squadmania에서 설정을 담당하는 클래스 입니다. ApplicationConfig 클래스는 외부 라이브러리에서 지원한 객체들을 Bean으로 등록해 설정을 담당하는 컴포넌트의 역할을 주입하게 됩니다.

userDetailsServices()
Spring Security에서 유저의 정보를 불러오는 인터페이스입니다. 해당 bean에서는 userRepository에 등록된 메서드를 통해 username을 파라미터로서 DB에 접근하여 해당 정보를 조회합니다.

AuthenticationProvider()
AuhthenticiationProvider의 절차를 수행합니다. 해당 메서드 내에 선언된 객체에서 @Bean으로 등록된 passwordEncoder()userDetailService()를 해당 인증요소로 설정합니다.

authenticationManager(AuthenticationConfiguration config)
해당 빈 객체는 ApplicationConfig 클래스가 @configuration을 통해 할당 받은 설정 영역을 호출합니다.

PasswordEncoder passwordEncoder()
해당 메서드를 통해 BCryptePasswordEncoder()의 종속성을 주입 받은 PasswordEncoder 객체를 호출합니다. JWT를 포함해, application 전반의 암호화를 담당할 때 사용됩니다.

4. 레퍼런스

https://jojoldu.tistory.com/27
https://velog.io/@composite/Spring-Component-Bean-%EC%95%8C%EA%B3%A0-%EC%93%B0%EA%B8%B0
https://melonicedlatte.com/2021/07/11/232800.html#google_vignette
https://jaeano.tistory.com/76
https://velog.io/@backtony/Spring-AOP-%EC%B4%9D%EC%A0%95%EB%A6%AC
https://code-lab1.tistory.com/193
https://steady-coding.tistory.com/594
https://yhmane.tistory.com/129
https://devscb.tistory.com/116


비문, 오탈자와 코드 오류 및 잘못된 지식에 대한 지적 및 질문은 언제나 환영합니다.

profile
프로개발자를 지망하는.

0개의 댓글