평범한 연구소

[Spring] 어노테이션 (Annotation) 본문

Spring Framework

[Spring] 어노테이션 (Annotation)

soyeonisgood 2022. 11. 10. 00:01

Annotation

- 어노테이션의 사용으로 설정파일을 간결화하고 객체 또는 메소드의 매핑을 명확히 할 수 있다.

- Java code로 설정하므로 type safe, Spring이 빠르게 container 설정한다.

- Annotation이 클래스(또는 메소드) 상단에 추가되면서 설정이 구성되기 때문에 클래스 파일만 보아도 어떤 스프링 설정이 적용된 클래스인지 한눈에 알 수 있다.

- 설정이 변경될 경우 Application code 클래스 파일까지 수정해주어야한다. (개발자가 수정)

- 의존성 주입 방법

  • 생성자 주입 (Constructor Injection) 
  • Setter 메소드 주입 (Setter Injection)
  • 필드 주입 (Field Injection)

 

<context:annotation-config/>

어노테이션은 기본적으로 활성화되지 않기 때문에 xml에서 활성화 작업이 필요하다.

 - 스프링 컨텍스트에 의해 생성되어 저장된 bean들에 대해서 @Autowired와 @Qualifier 등 인식.

 -  @Autowired, @Qualifier, @Resource, @PostConstruct, @PreDestroy ...

 

<context:component-scan/>  또는  @Component

특정 패키지에 위치한 클래스를 스프링 빈으로 자동 등록해주는 설정 방식. @Autowired, @Qualifier, @Resource, @Inject 같은 어노테이션도 활성화되므로 <context:annotation-config/> 사용 불필요하다.

 - @Component

  • 클래스 이름의 첫 문자를 소문자로 바꾼 것을 빈 이름(id)로 등록.

 - @Component("beanName")

  • 빈 이름(id)를 지정하여 빈 등록.

 

<context:component-scan base-package="com.anno.user7"/>
package com.anno.user6;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class User {
	
	@Autowired 
	private UserService userServiceImpl;
	
	public void write() {
		System.out.println("-- @Component : 빈 생성 --");
		System.out.println(userServiceImpl.message());
	}

}
package com.anno.user6;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component
public class User2 {
	@Autowired
	@Qualifier("user6.userServiceImpl2") // @Autowired와 함께 사용하며, 이름을 이용하여 의존성 주입
	private UserService userService;

	public void write() {
		System.out.println("-- @Component : 생성 --");
		System.out.println(userService.message());
	}

}
package com.anno.user6;

import org.springframework.stereotype.Component;

/*
 - @Component
 	: 자동으로 빈을 등록(객체 생성)
 	: 빈의 이름은 클래스명의 첫글자를 소문자로 하는 클래스명.
 		=> userServiceImpl
 	: 동일한 빈 이름이 2개 이상이 있으면 에러 발생.
 
*/

@Component
public class UserServiceImpl implements UserService {
	private String name;
	private String tel;
	private int age;
	
	public UserServiceImpl() {
		this.name = "김자바";
		this.tel = "010-1111-2222";
		this.age = 20;
	}
	
	@Override
	public String message() {
		String s = name + " : " + tel + " : " + (age + age>=19?"성인":"미성년자");
		
		return s;
	}
	
}
package com.anno.user6;

import org.springframework.stereotype.Component;

// 빈의 이름을 부여하여 빈 등록
@Component("user6.userServiceImpl2")
public class UserServiceImpl2 implements UserService {
	private String name;
	private String tel;
	private int age;
	
	public UserServiceImpl2() {
		this.name = "다자바";
		this.tel = "010-1111-2222";
		this.age = 20;
	}
	
	@Override
	public String message() {
		String s = name + ", " + tel + ", " + age + (age>=19?", 성인":", 미성년자");
		
		return s;
	}
	
}

 

의존성 주입 어노테이션

@Autowired

 - 주입하려고 하는 객체의 타입이 일치하는 객체를 자동으로 주입.

 - 필드, 생성자, Setter 메소드, 일반 메소드에 붙일 수 있다.

 - 필드에 붙이면 Setter를 통해 주입, Setter가 없으면 컴파일 과정에서 자동으로 추가.

 - 필드, Setter 메소드에 붙여서 사용할 경우, 반드시 기본 생성자가 정의되어 있어야 한다.

@Qualifier

 - 동일한 타입의 빈 객체가 여러 개 정의되어 있는 경우 특정 빈을 주입할 수 있도록 설정. <bean> 태그 하위에 <qualifier> 태그를 설정하여 특정 빈을 삽입할 수 있게 설정한다.

 - 단독으로 사용할 수 없다. @Autowired 어노테이션과 함께 사용되며, @Autowired이 적용된 주입 대상에 설정한다.

package com.anno.user2;

import org.springframework.beans.factory.annotation.Autowired;

public class User {
	// 동일한 타입이 둘 이상이면 필드명과 동일한 이름을 갖는 빈을 주입하며, 동일한 이름이 없으면 에러 발생
	@Autowired 
	private UserService userService;
	
	public void write() {
		System.out.println("-- 어노테이션 : 동일한 타입이 둘 이상인 경우 --");
		System.out.println(userService.message());
	}

}
package com.anno.user2;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

public class User2 {
	@Autowired
	@Qualifier("userService2") // @Autowired와 함께 사용하며, 이름을 이용하여 의존성 주입
	private UserService userService;

	public void write() {
		System.out.println("-- @Autowired, @Qualifier : 동일한 타입이 둘 이상인 경우 --");
		System.out.println(userService.message());
	}

}

 

③ @Resource

 - 주입할 객체의 이름(id)이 일치하는 객체를 자동으로 주입.

 - Java 제공.

 - 생성자에 붙일 수 없다. 필드, 입력 파라미터 하나인 Setter 메소드에 가능. 

 - 필드에 직접 정의하는 경우 Setter 정의하지 않아도 된다.

 - 기본 생성자가 정의되어 있어야한다.

package com.anno.user3;

import javax.annotation.Resource;

public class User {
	
	@Resource	// 자바가 제공하는 어노테이션. 이름으로 빈의 의존성 주입
				// name 속성을 생략한 경우, 필드와 동일한 이름을 갖는 빈 주입
	private UserService userService;
	
	public void write() {
		System.out.println("-- @Resource 어노테이션 : name 속성을 사용하지 않는 경우 --");
		System.out.println(userService.message());
	}

}
package com.anno.user3;

import javax.annotation.Resource;

public class User2 {
	@Resource(name = "userService2")
	private UserService userService;

	public void write() {
		System.out.println("-- @Resource : name 속성을 사용한 경우 --");
		System.out.println(userService.message());
	}

}

 

④ @Injection

 - @Autowired 와 유사, 주입할 객체의 타입이 일치한 객체를 자동으로 주입한다.

 - Java 제공. javax.inject 의존성 추가해야함.

 - 필드, 생성자, Setter에 붙일 수 있다.

⑤ @Named

 - @Autowired의 @Qualifier와 유사.

 - 빈 이름(id) 지정.

package com.anno.user4;

import javax.inject.Inject;

public class User {
	
	@Inject // 자바가 제공. 타입으로 의존성 주입. 동일한 타입이 둘 이상이면 이름으로 빈 의존성 주입
	private UserService userService;
	
	public void write() {
		System.out.println("-- @Inject 어노테이션 : 타입으로 의존성 주입 --");
		System.out.println(userService.message());
	}

}
package com.anno.user4;

import javax.inject.Inject;
import javax.inject.Named;

public class User2 {
	@Inject
	@Named("userService2")
	private UserService userService;

	public void write() {
		System.out.println("-- @Inject, @Named : 타입과 이름으로 의존성 주입 --");
		System.out.println(userService.message());
	}

}

 

 

 


 

자바 기반 Bean 설정

@Configuration

 - 자바 클래스를 스프링 환경설정 파일로 인식. XML이 아닌 자바코드를 이용하여 생성할 빈 객체 그리고 각 빈과의 연관 등 처리 가능.

 - @Configuration을 사용한 클래스는 스프링에서 사용하는 빈 자체로도 인식된다.

 

② @Bean  

 - @Component와 마찬가지로 스프링 컨테이너에 Bean을 등록하도록 하는 메타데이터를 기입하는 어노테이션.

 - 개발자가 직접 제어 불가능한 외부 라이브러리를 빈으로 등록할 때 사용한다.

    (@Component는 개발자가 직접 작성한 클래스를 빈으로 등록할 때 사용.)

 - 1개 이상의 @Bean을 사용한 클래스의 경우 반드시 @Configuration을 명시해주어야 한다.

package com.config.user2;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration // 스프링 환경 설정 파일
@ComponentScan(basePackages = {"com.config.user2"}) // 어노테이션 활성화
public class SpringConfig {

	// @Bean : 외부 라이브러리의 객체를 생성해야하는 경우에 사용
	// 하나 이상의 @Bean 있으면, @Configuration 필요.
	
	@Bean // 빈의 이름은 기본적으로 메소드명이다.
	public UserService userServiceDevice() {
		return new UserServiceImpl();
	}
	
	@Bean(name = "user2.user", initMethod = "init", destroyMethod = "destroy")
	public User userDevice() {
		return new User();
	}
}

 

@ComponentScan

 - @Component 어노테이션 및 streotype(@Service, @Repository, @Controller 등) 어노테이션이 부여된 Class들을 자동으로 Scan하여 Bean으로 등록해주는 역할

package com.config.user2;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration // 스프링 환경 설정 파일
@ComponentScan(basePackages = {"com.config.user2"}) // 어노테이션 활성화
public class SpringConfig {

	// @Bean : 외부 라이브러리의 객체를 생성해야하는 경우에 사용
	// 하나 이상의 @Bean 있으면, @Configuration 필요.
	
	@Bean // 빈의 이름은 기본적으로 메소드명이다.
	public UserService userServiceDevice() {
		return new UserServiceImpl();
	}
	
	@Bean(name = "user2.user", initMethod = "init", destroyMethod = "destroy")
	public User userDevice() {
		return new User();
	}
}

 

④ @PropertySource

 - 클래스 위에 붙임. 프로퍼티 파일의 값이 Environment 객체에 자동으로 주입.

 - @Autowired 후 getProperty("속성명") 으로 프로퍼티 값 확인 가능.

@Autowired
private Environment env;

 - @Value를 통해 프로퍼티 파일의 값을 필드 등에 주입 가능.

join.name=\uC815\uC18C\uC5F0
join.tel=010-1111-1111
join.age=20
package com.config.user3;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

@Configuration // 스프링 환경 설정 파일
@ComponentScan(basePackages = {"com.config.user3"}) // 어노테이션 활성화
@PropertySource("classpath:com/config/user3/main.properties") // 프로퍼티파일 읽기
public class SpringConfig {
}
package com.config.user3;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

// @Value("${프로퍼티이름}") => 프로퍼티의 값 반환
// @Value("${user.name}") => 예약어. 컴퓨터 사용자명. 쓰면 안된다!

@Service
public class UserServiceImpl implements UserService{
	private @Value("${join.name}") String name;
	private @Value("${join.tel}") String tel;
	private @Value("${join.age}") int age;
	
	@Override
	public String message() {
		String s = name + " : " + tel + " : " + age;
		s += age >= 19 ? ",성인" : ",미성년자";
		
		return s;
	}
	
}