ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Java] Annotation, Reflection, Lombok, Spring Bean
    Programming/Java 2024. 3. 14. 13:49
    728x90

    Annotation

    어노테이션은 메타데이터(Metadata)라고도 불린다.

     

    ● 컴파일러에게 정보 알림

      컴파일할 때 설치(deployment)시의 작업을 지정

      실행할 때 별도의 처리가 필요

     

    클래스, 메소드, 변수 등 모든 요소에 선언할 수 있다.

    어노테이션은 상속이 안된다. 미리 만들어 놓은 어노테이션을 확장하는 것이 불가능하다.

     

    어노테이션에 선언한 값을 확인하기 위해 Reflection을 사용한다.

    리플랙션으로 클래스에 부여한 어노테이션 값을 취득할 수 있다.

     

    기본 제공 3가지

    JDK6까지는 미리 정해져 있는 어노테이션은 3개이다.

    1. @Override

    해당 메소드가 부모 클래스에 있는 메소드를 Override했다는 것을 명시적으로 선언.

    제대로 Override했는지 확인하는 수단으로도 사용할 수 있다.

    2. @Deprecated

    만들어져 있는 클래스나 메소드가 더 이상 사용되지 않는 경우 컴파일러에게 알려주는 역할

    컴파일 결과에는 "경고"가 있을 뿐이지 "에러"는 없다. 컴파일은 완료되었기 때문에 클래스 파일은 생성되어 있다.

    하위 호환성 때문에 필요하다.

    3. @SupressWarnings

    컴파일러가 경고할 필요가 없다고 선언.

    @SupressWarning("deprecation") 처럼 소괄호 안에 속성값을 문자열로 지정한다.

    deprecation으로 지정하면 경고 메시지가 나오지 않는다.

     

     

    선언

    1. @Target

    어노테이션을 어떤 것에 적용할지를 선언.

    2. @Retention

    얼마나 오래 어노테이션 정보가 유지되는지를 선언

    3. @Document

    어노테이션에 대한 정보가 Javadocs(API)문서에 포함된다는 것을 선언

    4. @Inherited

    모든 자식 클래스에서 부모 클래스의 어노테이션을 사용 가능하다는 것을 선언

     

    @Target(ElementType.METHOD)

    요소 타입 대상
    CONSTRUCTOR 생성자 선언시
    FIELD enum상수를 포함한 필드(field)값 선언 시
    LOCAL_VARIABLE 지역 변수 선언시
    METHOD 메소드 선언시
    PACKAGE 패키지 선언시
    PARAMETER 매개 변수 선언시
    TYPE 클래스, 인터페이스, enum 등 선언시

     

     

    @Retention(RetentionPolicy.RUNTIME)

      대상
    SOURCE 어노테이션 정보가 컴파일시 사라짐
    CLASS 클래스 파일에 있는 어노테이션 정보가 컴파일러에 의해서 참조 가능함. 하지만, 가상머신(Virtual Machine)에서는 사라짐
    RUNTIME 실행시 어노테이션 정보가 가상 머신에 의해서 참조 가능

     

     

    동작 원리

    Compilation Prcess

     

    AST(Abstract Syntax Tree), Annotation Processor가 나온다.

    AST는 자바 컴파일러가 클래스코드를 이해하기 위한 트리 구조 코드이다.

     

    어노테이션은 컴파일 중에 처리된다.

    Annotation processor가 동작하기 전에는 그냥 주석과 다를 게 없다.

     

    모든 자바 파일은 파서에 공금되어 추상 구문 트리를 생성하고 컴파일러의 심볼 테이블을 채운다.

    그런 다음 각 어노테이션에 대해 해당 어노테이션 프로세서가 호출되어 새 소스 파일을 생성한다. (파싱되면 새 소스 파일 생성)

    더 이상 파싱되지 않아 새 소스 파일이 생성되지 않으면 마지막으로 Syntax Tree(구문 트리)가 클래스 파일로 변환한다.

     

    간단히 하면,

    Annotation Processor가 Annotation이 붙은 코드들을 수집해서 바이트코드인 Class File로 변환한다.

    이 과정에서 Parser는 수집(실행)되지 않은 Annotation Processor가 있는지 확인한 후 모두 수행할 때까지 반복한다.

     

    어노테이션 프로세서는 새 소스 파일만 생성할 수 있고, 기존 파일은 수정할 수 없다는 점이 중요하다.

    또한 javac는 컴파일 중에서 자체 JVM내에서 어노테이션 프로세서를 실행한다는 점도 중요하다.

    즉, 소스 파일을 생성하고 테이스를 작성하기 위해 임의의 java라이브러리를 사용할 수 있다.

     

    Annotation Processor

    일반적으로 모든 어노테이션 프로세서를 실행하려면 먼저 등록해야한다.

    META-INF/service디렉토리에 javax.annotation.processing.Processor 파일을 생성하여 수행된다.

    파일의 각 줄에는 javac가 자동으로 감지하여 실행하는 어노테이션 프로세서를 지정할 수 있다.

     

     

     

    Spring프레임워크는 런타임에 객체 지향 프로그래밍을 사용하여 Java애플리케이션에 기능을 추가하는데 많이 사용된다.

     

     

     

    Reflection

    리플랙션은 구체적인 클래스 타입을 알지 못하더라도 그 클래스의 메서드, 타입, 변수들에 접근할 수 있도록해주는 자바 API이다.

    컴파일 시간이 아닌 실행 시간에 동적으로 특정 클래스의 정보를 추출할 수 있는 프로그래밍 기법이다.

    (런타임에 객체의 속성을 검색, 검사 및 조작)

    힙영역에 로드된 Class타입의 객체를 통해, 접근 제어자 상관없이 원하는 클래스의 정보에 접근해서 조작할 수 있도록 지원하는 API이다.

     

    언제 사용?

    ● 동적으로 클래스를 사용해야할 때 사용

       작성 시점에는 어떤 클래스를 사용해야 할지 모르지만 런타임 시점에서 가져와 실행해야 하는 경우에 사용한다.

    ● 프레임워크나 IDE에서 동적 바인딩을 이용한 기능을 제공한다.

    ● 리플랙션 사용 예시

      - IntelliJ의 자동완성 기능

      - 스프링 어노테이션

     

    리플랙션에서 제공하는 클래스

    ●  Class : 클래스 정보 확인

    ●  Constructor

    ●  Method : 메소드 정보 확인

    ●  Field

     

    장점

    1. 유연성과 확장성

    구체적인 클래스를 아맂 못해도 동적으로 클래스를 만들어서 의존 관계를 맺어줄 수 있다.

    개발 규모가 큰 스프링인 경우, 리플랙션을 이용한 Dynamic Proxy를 통해서 @AutoWired, @Service, @Controller, @Repository와 같은 DI어노테이션을 활용한다.

     

    2. 접근 제한 상관없이 테스트 가능

    접근 제어자가 private이더라도 얼마든지 접근해서 조작할 수 있다.

     

    단점

    1. 캡슐화 저해

    private 데이터에도 접근이 가능하여 캡슐화가 깨지는 위험성이 있다.

     

    2. 성능 이슈

    단순 접근보다 리플랙션을 이용한 접근이 느리다.

    자주 호출되는 성능에 민감한 코드에서는 적용하지 않아야 한다.

     

    3. 디버깅의 어려움

    컴파일 단계가 아닌 런타임 단계에서 에러가 발생함으로써 생기는 디버깅의 어려움이 더 크다.

     

     

    Lombok

    여러가지 @어노테이션을 제공하고 컴파일 과정에서 자동으로 개발자가 원하는 메소드를 생성/주입 방식으로 동작하는 라이브러리.

    반복되는 메소드를 어노테이션을 사용해서 자동으로 작성해주는 라이브러리이다.

    롬북을 이용해서 작성한 코드는 컴파일 과정에서 어노테이션을 이용해 코드를 생성하고 .class에 자동 컴파일 된다.

     

    1. Ant 빌드 도구를 사용한다.

    2. .class파일을 .lombok이라는 바이너리로 변환한다.

     

    프로젝트에 적용하면 lombok-[versuib].jar로 빌드 도구(Maven, Gradle)에 있다.

     

    종류

    @Getter, @Setter

    @NonNull : null check해준다.

    @ToString

    @EqualsAndHashCode

    @Data

    @Value

    @NoArgsConstructor, @RequiredArgsConstructor, @AllArgsConstructor

    @Builder

    등등

     

     

     

    GitHub - projectlombok/lombok: Very spicy additions to the Java programming language.

    Very spicy additions to the Java programming language. - projectlombok/lombok

    github.com

     

     

    Spring Bean

    Spring Ioc컨테이너가 관리하는 자바 객체를 Bean(빈)이라고 한다.

    IOC : 제어의 역전

    자바 프로그램에서는 각 객체들의 프로그램의 흐름을 결정하고 생성, 조작 작업을 사용자가 제어하는 구조이다.

    하지만 IOC가 적용된 경우, 객체의 생성을 특별한 관리 위임 주체에게 맡긴다. 

    사용자가 객체를 직접 생성하지 않고 객체의 생명주기를 컨토롤하는 주체는 다른 주체가 된다.

    즉, 사용자의 제어권을 다른 주체에게 넘기는 것을 IOC라고 한다.

     

    스프링에서는 new를 이용해서 생성한 객체가 아니라, 스프링에 의해 관리당하는 자바 객체를 사용한다.

    스프링에 의해 생성되고 관리되는 자바 객체를 Bean이라고 한다.

    스프링 프레임워크는 Spring Bean을 얻기 위해 ApplicationContext.getBean() 메소드를 사용하여 Spring에서 직접 자바 객체를 얻어서 사용한다.

     

    Spring Bean을 Spring IoC Container에 등록하는 방법

    1. 자바 어노테이션을 사용하는 방법

    자바에서 기본으로 제공하는 메타 어노테이션을 사용한다.

    @Component

    어노테이션이 등록되어 있는 경우에는 Spring이 어노테이션을 확인하고 자체적으로 Bean으로 등록한다.

     

    예를 들어 

    Spring프로젝트에서 Controller를 등록할 때 @Controller 어노테이션을 사용한다.

    @Controller
    public class MemberController {
    
        @Autowired
        private MemberRepository memberRepository;
        
        @GetMapping("/signup")
        public String newMemeberForm(){
            return "members/new";
        }

     

    @Controller 어노테이션을 인텔리제이에서 ctrl눌러서 이동하면 아래와 같은 소스를 확인할 수 있다.

    @Controller어노테이션을 @Component어노테이션을 사용해서 Spring Bean에 등록한다.

    // Controller.java
    // -- 일부 생략 --
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Component
    public @interface Controller {
    	/**
    	 * The value may indicate a suggestion for a logical component name,
    	 * to be turned into a Spring bean in case of an autodetected component.
    	 * @return the suggested component name, if any (or empty String otherwise)
    	 */
    	@AliasFor(annotation = Component.class)
    	String value() default "";
    }

     

     

    2. Bean Configuration File에 직접 Bean등록하는 방법

    @Configuration,
    @Bean

    두개의 어노테이션을 이용하여 Bean을 등록할 수 있다.

     

    @Configuration어노테이션은 스프링 IoC container에게 해당 클래스가 Bean구성 Class임을 알려준다.

    -> @Bean 어노테이션을 해당 클래스의 메소드에 적용하면, @Autowired로 Bean을 부를 수 있다.

     

     

    3. XML 설정

     

    3-1. 직접 등록

    resource > application.xml 파일을 생성하여 <beans> 엘리먼트 안에 등록할 Bean정보를 입력한다.

    <?xml version="1.0" encoding="UTF-8" ?>
    <beans ...>
      <bean id="MyService"
            class="com.example.my.MyService">
        <property name="myRepository"
                  ref="myRepository"/>
      </bean>
      <bean id="MyRepository"
            class="com.example.my.MyRepository">
      </bean>
    </beans>

     

     

    3-1. Component-scan으로 등록

    <?xml version="1.0" encoding="UTF-8" ?>
    <beans ...>
      <context:component-scan base-package="com.example.my" />
    </beans>

    <context:component-scan>엘리먼트를 등록하여 컴포넌트 스캔을 통한 Bean등록할 것이라고 알려준다.

    base-package속성에 컴포넌트 스캔을 진행할 대상 루트 패키지를 작성한다.

    해당 패키지를 포함한 모든 하위 패키지의 Bean설정을 스캔하여 등록하게 된다.

     


    @Bean vs @Component

    ● @Bean

    개발자가 컨트롤이 불가능한 외부라이브러리들을 Bean으로 등록하고 싶은 경우에 사용

    ●  @Component

    개발자가 직접 컨트롤이 가능한 Class들의 경우에 사용한다. 개발자가 직접 작성한 Class를 Bean으로 등록하기 위한 어노테이션.

     

    개발자가 생성한 Class에 @Bean 선언가능? No!

    @Bean과 @Component는 각자 선언할 수 있는 타입이 정해져있어 해당 용도 외에는 컴파일 에러를 발생시킨다.

     

     

    SpringBoot

    spring boot를 자동으로 실행시켜주는 어노테이션으로 Bean등록은 두 단계로 진행된다.

    1) @ComponentScan을 통해 Component들은 Bean으로 등록

    2) @EnableAutoConfiguration을 통해 미리 정의해둔 자바 설정 파일들을 Bean으로 등록

     

    @ComponentScan

    @Component, @Service, @Repository, @Controller, @Configuration이 붙은 빈들을 찾아서 Context에 빈을 등록해 주는 어노테이션

     

    @EnableAutoConfiguration

    스프링 어플리케이션 컨텍스트를 만들 때 자동으로 설정하는 기능을 켠다.

    classpath의 내용에 기반해서 자동 생성해 준다. 만약 tomcat-embed-core.jar가 존재하면 톰캣 서버가 setting된다.

     


    모든 의존 관계를 자동으로 연결하여 Bean을 주입해주는 기능을 가진 어노테이션

      @Resource @Autowired  @Inject
     범용 Java에서 지원하는 어노테이션 Spring Framework에서 지원 Java에서 지원하는 어노테이션
    사용하는 위치 필드, 파라미터가 한개인 setter 메소드
    (기본 생성자 정의 필수)
    필드, 생성자, setter 메소드
    (기본 생성자 정의 필수)
    필드, 생성자, setter 메소드
    (기본 생성자 정의 필수)
    연결 또는 검색 방식
    (우선 순위)
    이름(id)이 일치하는 객체 자동 주입 (이름 -> 타입) 타입이 일치하는 객체 자동 주입 (타입 -> 이름) 타입이 일치하는 객체 자동 주입 (타입 -> 이름)
    특이사항     스프링에서만 사용 가능  
    강제 연결 하기  @Resource(name="id")
    id=> servlet-context.xml의 bean id
    @Autowired 
    @Qualifier("value")
    @Inject
    @Named("id")

     

     

    참고

    https://developer-youn.tistory.com/122

    https://www.adrianbartnik.de/blog/annotation-processing/

    https://docs.oracle.com/javase/tutorial/reflect/index.html

    https://tjdtls690.github.io/studycontents/java/2023-01-27-reflection01/

    https://docs.oracle.com/javase/8/docs/technotes/guides/language/annotations.html

    https://github.com/projectlombok/lombok/

    https://prinha.tistory.com/entry/자바-스프링-어노테이션-annotation의-정의와-종류

    https://luckydavekim.github.io/development/back-end/spring-framework/create-spring-bean/

     

     

     

    728x90

    'Programming > Java' 카테고리의 다른 글

    [Java] Stream  (1) 2024.06.16
    [Java] currentTimeMillis() nanoTime() Instant.now() uuid  (1) 2024.05.31
    [Java] Checked, Unchecked Exception  (0) 2024.03.13
    [Java] OOME, JVM8 메모리  (0) 2024.02.29
    [Java] Spring 빌드 Jar, War  (0) 2024.02.29

    댓글

© 2022. code-space ALL RIGHTS RESERVED.