스프링 부트 어노테이션
https://javatechonline.com/spring-boot-annotations-with-examples/
위의 문서를 번역한 내용이다.
어노테이션 기본
IoC 컨테이너는 무엇인가?
간단히 말하면, IoC는 빈(bean)을 생성할 때 의존성을 주입하는 컨테이너이다. IoC는 'Inversion Of Control'을 의미한다. 개발자가 객체를 직접 생성하는 대신에, IoC 컨테이너의 도움으로 클래스의 생성자를 사용하여 빈(bean) 자체가 의존을 생성 및 연관(association)을 제어한다. 그러므로, 이런 과정은 'Inversion of control'로 알려져 있다. 때로는 간단히 말해서 스프링 컨테이너라고 부른다.
org.springframework.beans와 org.springframework.context 패키지는 스프링 프레임워크의 IoC 컨테이너의 기본이다. ApplicationContext는 BeanFactory의 하위 인터페이스이다.
스프링 프레임워크에서 애플리케이션 컨텍스트(Application Context)는 무엇인가?
여러분들이 스프링 혹은 스프링 부트 프로젝트를 만들 때, 컨테이너 혹은 래퍼(wrapper)는 빈(bean)을 관리하기 위해 생성된다. 이는 단지 애플리케이션 컨텍스트이다. 하지만 스프링은 두 가지 컨테이너를 지원한다: 빈(bean) 팩토리와 애플리케이션 컨텍스트. 간단히 말하면, BeanFactory는 구성(configuration) 프레임워크와 기본 기능을 제공한다. 반면, ApplicationContext는 스프링의 AOP 기능과 쉽게 통합하는 것을 포함하여 더 많은 비즈니스 기능을 포함한다: 메시지 리소스 핸들링, 이벤트 발행, 그리고 웹 애플리케이션에서 사용되는 WebApplicationContext 같은 애플리케이션 계층 컨텍스트.
ApplicationContext는 BeanFactory의 완전한 슈퍼셋이고 스프링 IoC 컨테이션을 표현하는데 사용된다. 스프링 프레임워크는 프레임워크 전체 기능을 사용하는데 애플리케이션 컨텍스트를 추천한다.
게다가, 의존성 주입 및 오토와이어링(auto-wiring)은 애플리케이션 컨텍스트에서 수행된다.
org.springframeowork.context.ApplicationContext는 스프링 IoC 컨테이너를 나타내며 초기화 과정, 빈의 구성하고 모으는 역할을 관리한다. 컨테이너는 초기화 할 객체가 무엇이며 구성을 하고 메타데이터를 통해 빈을 모으는 역할을 한다. 구성 메타데이터는 3가지 포맷으로 포현될 수 있다: XML, 자바 어노테이션 혹은 자바 코드.
스프링 빈(Bean) 혹은 컴포넌트(Component)는 무엇인가?
애플리케이션이 시작되는 동안, 스프링은 객체를 초기화하고 그것을 애플리케이션 컨텍스트(IoC 컨테이너)에 추가한다. 애플리케이션 컨텍스트에서 이러한 객체들은 '스프링 빈' 혹은 '스프링 컴포넌트'라고 부른다. 이것들이 스프링에서 관리되기 때문에, 우리는 스프링 관리 빈 혹은 스프링 관리 컴포넌트라고 부른다.
컴포넌트 스캐닝(Component Scanning)은 무엇인가?
애플리케이션 컨텍스트에 기여할 수 있는 클래스를 찾는 과정을 컴포넌트 스캐닝이라고 부른다. 컴포넌트 스캐닝 동안, 스프링이 특정 어노테이션이 있는 클래스를 찾는다면, 스프링 빈/컴포넌트의 후보 대상 클래스로 판단되고 애플리케이션 컨텍스트에 추가된다. 스프링은 @ComponentScan 어노테이션을 통해 스프링 빈 후보를 인식할 수 있는 방법을 제공한다.
스프링 부트 애플리케이션에서 컴포넌트 스캐닝은 언제 사용될까?
기본적으로 @ComponentScan 어노테이션은 현재 패키지와 그 하위 패키지의 모든 컴포넌트를 스캔할 것이다. 만일 그것이 스프링 부트 애플리케이션이라면, 메인 클래스(@SpringBootApplication 어노테이션이 있는 클래스)를 포함하는 패키지 하위 모든 패키지가 암묵적으로 컴포넌트 스캔의 대상이 될 것이다. 그래서 여러분의 패키지가 메인 클래스를 포함하는 패키지 구조 하위에 없다면, 명시적인 컴포넌트 스캐닝을 설정할 필요가 있다.
스프링 어노테이션 vs 스프링 부트 어노테이션
스프링 부트 프레임워크는 스프링 프레임워크 라이브러리를 사용하여 만들어져 있고 XML 구성 방식을 제거한 것으로 우리는 알고 있다. 하지만 모든 스프링 프레임워크의 어노테이션은 여전히 스프링 부트에 적용될 수 있다. 게다가, 스프링 부트는 스프링 부트용 추가적인 어노테이션을 제공한다. 어떤 경우에는, 스프링 부트는 스프링 프레임워크 어노테이션을 더 많이 추가한 이후에 어노테이션을 만들었다.
빈(Bean)을 생성하기 위한 어노테이션
말할 필요도 없이, 빈을 생성하지 않고는 스프링 부트/스프링 프레임워크로 작업할 수 없다. 이제 이런 것들이 얼마나 중요한지 생각해 볼 수 있다.
@Configuration
우리는 클래스에 이 어노테이션을 적용한다. 우리가 클래스에 적용할 때, 해당 클래스는 구성파일로서 동작한다. 일반적으로 @Configuration 어노테이션이 있는 클래스는 XML 구성에서 <bean/> 태그와 같은 정의를 갖게 된다. 또한 자바 클래스를 사용하여 구성을 나타낸다. 게다가 클래스는 의존을 초기화하고 구성하는 메소드를 갖게 될 것이다. 예를 들면
@Configuration
public class AppConfig {
@Bean
public RestTemplate getRestTemplate() {
RestTemplate restTemplate = new RestTemplate();
return restTemplate;
}
}
이러한 메소드 방식으로 객체를 생성하는 장점은 오직 하나의 인스턴스만을 가지게 된다는 것이다. 여러분들은 필요할 때 여러 번 객체를 만들 필요가 없다. 코드에서 필요할 때 호출할 수 있다.
@Bean
우리는 메소드 수준에서 @Bean을 사용한다. 여러분이 스프링 xml 구성을 기억하고 있다면, XML <bean/> 요소와 유사하다. 이것은 스프링 빈을 만들고 일반적으로 *@Configuration에서 사용된다. 앞서 언급한 @Configuration이 있는 클래스(구성 클래스라고 부른다)는 객체를 초기화하는 메소드를 가지고 의존을 구성하게 된다. 그런 메소드는 *@Bean 어노테이션을 가지게 될 것이다.
기본적으로, 빈 이름은 메소드 이름과 동일하다. 초기화를 하고 실제 빈을 리턴한다. 어노테이션이 있는 메소드는 스프링 IoC 컨테이너에서 관리되는 빈을 만든다. 예를 들면
@Configuration
public class AppConfig {
@Bean
public Employee employee() {
return new Employee();
}
@Bean
public Address address() {
return new Address();
}
}
비교를 위해서, 위의 구성은 다음 스프링 XML 방식과 동일하다.
<beans>
<bean name="employee" class="com.dev.Employee" />
<bean name="address" class="com.dev.Address" />
</beans>
어노테이션은 init-method, destroy-method, autowiring, lazy-init, dependency-check, depends-on과 scope과 같은 <bean/>으로 제공되는 대부분의 속성을 제공한다.
@Component
@Component 어노테이션은 또한 중요하고 대부분 클래스 레벨에서 사용된다. 이것은 클래스가 스프링에서 관리되는 빈/컴포넌트라는 것을 알려주는 스테레오 타입 어노테이션이다. @Component는 클래스 수준 어노테이션이다. 다른 타입들은 @Component의 세분화된 요소이다.
컴포넌트 스캐닝 동안, 스프링 프레임워크는 자동으로 @Component*를 가진 클래스를 찾고 애플리케이션 컨텍스트에 스프링 빈으로 등록한다. 클래스에 *@Component 어노테이션을 적용하는 것은 그 클래스를 스프링에서 관리되는 빈/컴포넌트로 동작하도록 표시하는 것을 나타낸다. 예를 들어 아래 코드를 보면
@Component
class MyBean {}
위와 같이 클래스를 만들 때, 스프링은 'myBean' 이름의 인스턴스를 만들것이다. 기본적으로 클래스를 초기화하는 빈은 소문자로 시작하는 클래스 이름과 동일하다는 것을 기억하자. 하지만, 아래와 같이 어노테이션 인수를 사용하여 다른 이름을 명시할 수 있다.
@Component("myTestBean")
class MyBean {}
@Controller
@Controller 어노테이션이 있는 클래스는 스프링 MVC 프로젝트에서 컨트롤러로 동작하는 것을 나타낸다.
@RestController
@RestController 어노테이션이 있는 클래스는 스프링 REST 프로젝트에서 컨트롤러로 동작하는 것을 나타낸다.
@Service
@Service 어노테이션이 있는 클래스는 서비스 계층이고 애플리케이션의 비즈니스 로직을 포함하는 것을 나타낸다.
@Repository
@Repository 어노테이션이 있는 클래스는 데이터 접근 계층이며 애플리케이션에서 데이터베이스로 데이터 접근 로직을 포함하는 것을 나타낸다.
@Bean vs @Component
@Component는 클래스 수준 어노테이션인 반면 *@Bean은 메소드 수준 어노테이션이고 메소드 이름은 bean 이름을 나타낸다. *@Bean 어노테이션은 클래스 내에서 사용되어야 하며 클래스는 @Configuration 어노테이션이 있어야 한다. 하지만, @Component는 @Configuration과 함께 사용되지 않는다. @Component는 클래스패스 스캐닝을 사용해 자동으로 감지하고 빈을 구성한다. 반면 @Bean은 자동으로 감지하지 않고 명시적으로 단일 빈을 선언한다.
Configuration 어노테이션
@ComponentScan
스프링 컨테이너는 @ComponentScan*을 통해 스프링에서 관리하는 컴포넌트를 감지한다. 여러분이 이 어노테이션을 사용하면, 스프링 컨테이너에게 컴포넌트를 찾을 위치를 알려주는 것이다. 스프링 애플리케이션이 시작할 때, 스프링 컨테이너는 찾을 위치 정보가 필요하고 애플리케이션 컨텍스트를 가진 스프링 컴포넌트를 등록한다. 사전 정의된 프로젝트 패키지로 부터 *@Component, @Controller, @Service, @Repository와 같은 스테레오 타입 어노테이션을 가진 모든 클래스를 자동으로 스캔할 수 있다.
@ComponentScan 어노테이션은 어노테이션이 있는 컴포넌트를 스프링이 스캔할 수 있도록 요청하는 @Configuration과 함께 사용된다. @ComponentScan은 또한 기본 패키지를 설정하고 backPackages를 사용하여 기본 패키지 클래스를 설정하거나 @ComponentScan의 backPackageClasses 속성을 나타내는데 사용될 수 있다. 예를 들면:
import com.springframework.ajavatechonline.example.package2.Bean1;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(backPackage = {"com.springframework.javatechonline.example.package1",
"com.spectraframework.javatechonline.example.package3",
"com.spectraframework.javatechonline.example.package4"},
basePackageClasses = Bean1.class
)
public class SpringApplicatoinComponentScanExample {
...
}
여기서 @ComponentScan 어노테이션은 하위 서브 패키지를 포함한 3개의 패키지를 명시하는데 backPackages 속성을 사용하고 스프링 컨테이너를 스캔한다. 게다가 어노테이션 또한 스프링 부트가 스캔할 패키지인 Bean1 클래스를 표시하는데 backPackageClasses 속성을 사용한다. 게다가 이 기본 설정으로, 스프링 부트는 현재 패키지와 그 하위 패키지(스프링 부트 메인 클래스를 포함)의 컴포넌트를 자동으로 스캔할 것이다.
@Import
@Configuration 어노테이션이 있는 여러 개의 자바 구성 클래스를 가지고 있다고 생각해보자. @Import*는 하나 이상의 자바 구성 클래스를 임포트한다. 게다가, 여러 개의 구성 클래스를 그룹핑할 수 있다. 우리는 이 어노테이션을 하나의 *@Configuration 클래스를 논리적으로 다른 곳에서 정의된 빈 정의를 임포트한다. 예를 들면:
@Configuration
@Import({ DataSourceConfig.class, MyCustomConfig.class })
public class AppConfig extends ConfigurationSupport {
// DataSourceConfig나 MyCustomConfig의 @Bean 메소드를 참조하는 @Bean 메소드가 여리기 위치할 수 있다.
}
@Configuration
public class DataSourceConfig {...}
@Component
public class MyCustomConfig {...}
@PropertySource
만일 여러분이 STS같은 IDE를 사용해서 스프링 부트 스타터 프로젝트를 만든다면, application.properties는 기본적으로 resources 폴더 하위에 위치한다. 반면, 편의성을 고려해서 @PropertySource를 사용하여 properties 파일의 이름과 위치를 제공할 수 있다. 게다가, 이 어노테이션은 스프링 환경에 PropertySource를 추가하는데 편리하고 선언적인 메카니즘을 제공한다. 예를 들면:
@Configuration
@PropertySource("classpath:/com/dev/javatechonline/app.properties")
public class MyClass {
}
@PropertySource (여러 Property 위치를 사용하는 경우)
물론, 프로젝트에 여러 개의 property를 사용한다면, @PropertySources 어노테이션을 사용할 수 있고 @PropertySource 배열로 나타낼 수 있다.
@Configuration
@PropertySources({
@PropertySource("classpath:/com/dev/javatechonline/app1.properties"),
@PropertySource("classpath:/com/dev/javatechonline/app2.properties")
})
public class MyClass {}
게다가, 우리는 아래와 같이 다른 방법으로 동일한 코드를 작성할 수 있다. @PropertySource 어노테이션은 자바 8 규약에 따라 반복적으로 사용될 수 있따. 그러므로, 자바 8 이상을 사용한다면, 여러 개의 property 위치를 정의할 수 있다. 예를 들면:
@Configuration
@PropertySource("classpath:/com/dev/javatechonline/app1.properties")
@PropertySource("classpath:/com/dev/javatechonline/app1.properties")
public class MyClass {}
Note: properties의 이름이 동일하다면, 마지막에 있는 정보가 우선 사용된다.
@Value
우리는 이 어노테이션으로 변수 값을 스프링에서 관리하는 빈의 필드로 주입할 수 있다. 필드에 적용하거나 메소드 파라미터 레벨로 적용할 수도 있다. 예를 들면, 프로퍼티 파일을 우선 정의하고 @Value를 사용하며 properties 값을 주입하자.
server.port=9898
server.io=10.10.10.9
emp.department=HR
columnNam
이제 아래와 같이 @Value를 사용하여 server.ip값을 주입하자.
@Value("${server.ip}")
private String serverIP;
@Value 기본 값
우리가 properties 파일에 프로퍼티를 정의하지 않았다고 생각해보자. 그런 경우에 프로퍼티의 기본 값을 제공할 수 있다. 여기에 예제가 있다:
@Value("${emp.department:Admin}")
private String empDepartment;
여기서, Admin 값은 emp.department property로 주입될 것이다. 하지만 properties file에 프로퍼티를 정의했다면, 프로퍼티 값은 오버라이드 될 것이다.
Note: 동일한 프로퍼티가 시스템 프로퍼티와 프로퍼티 파일에 정의된다면, 시스템 프로퍼티가 우선 사용될 것이다.
여러 값을 가진 @Value
때로는 단일 프로퍼티에 여러 값을 주입할 필요가 있다. 우리는 프로퍼티 파일에 단일 프로퍼티의 콤마(,)로 구분된 값으로 편리하게 정의할 수 있다. 게다가 우리는 배열 형식으로 프로퍼티에 손쉽게 주입할 수 있다.
@Value("${columnNames}")
private String [] columnNames;
스프링 부트 용 어노테이션
스프링 부트용 어노테이션은 스프링 부트 내에서 사용된다. 하지만 내부적으로는 대부분 스프링 프레임워크에서 제공되고 확장되는 어노테이션을 사용한다.
SpringBootApplication (@Configuration + @ComponentScan + @EnableAutoConfiguration)
스프링 부트를 사용해본 모든 사람들은 의도적이던 아니던 이 어노테이션을 사용해야 한다. IDE를 사용해 스프링 부트 스타터 프로젝트를 만든다면, 이 어노테이션은 자동으로 생긴다. 이 어노테이션은 main() 메소드를 가지고 있는 메인 클래스에 적용된다. 메인 클래스는 스프링 부트 애플리케이션에서 두 가지 목적을 가지고 있다: 구성(configuration)과 부트스트래핑(bootstrapping)
사실 @SpringBootApplication*은 기본 값으로 세 가지 어노테이션의 조합이다. 그 값은 *@Configuration, @ComponentScan, @EnableAutoConfiguration이다. 그래서 @SpringBootApplication은 3-in-1 어노테이션이라고 할 수 있다. 이것은 스프링 부트 어노테이션 주제에서 중요한 어노테이션이다.
@EnableAutoConfiguration: 스프링 부트의 자동 구성을 가능하게 한다.
@ComponentScan: @Component를 스프링 애플리케이션 컨텍스트에서 컴포넌트 빈으로 등록되도록 스캔을 가능하게 한다.
@Configuration: 컨텍스트에서 빈을 추가로 등록하거나 추가 구성 클래스를 임포트하게 한다.
우리는 또한 커스트마이징이 필요하다면 @SpringBootApplication 위치에 개별적으로 세 가지 어노테이션을 사용할 수 있다.
@EnableAutoConfiguration
@EnableAutoConfiguration은 스프링 부트 애플리케이션 내의 클래스 패스에 존재하는 빈(bean)의 자동 구성을 가능하게 한다. 간단히 말하면, 이 어노테이션은 스프링 부트로 하여금 애플리케이션 컨텍스트를 자동으로 구성하는 것이다. 그러므로, 클래스 패스 내의 jar파일에 포함된 빈과 애플리케이션 내에서 정의된 빈을 생성하고 등록한다. 예를 들면, 스프링 부트 스타터 프로젝트를 만들 때 스프링 웹과 스프링 시큐리티 의존을 사용하면, 스프링 부트는 톰캣, 스프링 MVC, 스프링 시큐리티를 자동으로 구성한다.
게다가, 스프링 부트는 @EnableAutoConfiguration을 선언하는 클래스 패키지를 기본 패키지로 판단한다. 그러므로, 우리가 애플리케이션 루트 패키지에 이 어노테이션을 적용한다면, 모든 서브 패키지와 클래스가 스캔될 것이다. 그 결과 @ComponentScan을 사용해 패키지 이름을 명시적으로 선언할 필요가 없을 것이다.
그 뿐만 아니라, @EnableAutoConfiguration은 클래스들을 auto-configuration에서 제외하는 수동 설정도 가지고 있다. 만일 클래스가 자동으로 구성되지 못하게 하고 싶다면, 비활성화하도록 제외 속성을 사용할 수 있다. 다른 설정은 제외할 클래스 리스트를 선언하는 excludeName이다. 예를 들면, 아래 코드
@EnableAutoConfiguration에서 'exclude' 사용
@Configuration
@EnableAutoConfiguration(exclude={WebSocketMessagingAutoConfiguration.class})
public class MyWebSocketApplication {
public static void main(String[] args) {
...
}
}
@EnableAutoConfiguration에서 'excludeName' 사용
@Configuration
@EnableAutoConfiguration(excludeName={"org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration"})
public class MyWebSocketApplication {
public static void main(String[] args) {
...
}
}
@SpringBootConfiguration
이 어노테이션은 스프링 부트 프레임워크의 한 부분이다. 하지만 @SpringBootApplication이 그 값을 상속한다. 그래서 애플리케이션이 @SpringBootApplication을 사용한다면, 이미 @SpringBootConfiguration을 사용하고 있는 것이다.
게다가, @Configuration 어노테이선의 또 다른 선택지로 작용한다. 주요 차이점은 @SpringBootConfiguration은 자동으로 발견되는 구성을 가능하게 한다. @SpringBootConfiguration은 클래스가 구성을 제공하고 클래스 수준에서 적용된다는 것을 나타낸다. 특별히 이런 것을 단위/통합 테스트에서 유용하다. 예를 들면 아래 코드를 보자.
@SpringBootConfiguration
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
@Bean
public IEmployeeService employeeService() {
return new EmployeeServiceImpl();
}
}
@ConfigurationProperties
스프링 프레임워크는 프로퍼티 파일에서 값을 주입하는 다양한 방법을 제공한다. 그것 중 하나는 @Value 어노테이션을 사용하는 것이다. 다른 방식은 프로퍼티 값을 빈으로 주입하기 위해 구성 빈에서 @ConfigurationProperties를 사용하는 것이다. 하지만 두가지 방식의 차이점과 *@ConfigurationProperties를 사용하는 장점이 무엇인지 이해하게 될 것이다. 이제 *@ConfigurationProperties 어노테이션을 사용하여 application.properties 혹은 다른 프로퍼티를 사용하여 프로퍼티 값을 주입해보자.
우선, 다음과 같이 application.properties 파일을 정의해보자. 개발 작업 환경에 대한 몇 개의 프로피터를 정의하고 있다고 가정하자. 그래서 다음과 같이 'dev' 로 시작하는 프로퍼티를 나타낸다.
dev.name=Development Application
dev.port=8090
dev.dburl=mongodb://mongodb.example.com:27017/
dev.dbname=employeeDB
dev.dbuser=admin
dev.dbpassword=admin
이제, getter와 setter를 가진 빈을 만들고 @ConfigurationProperties 어노테이션을 붙이자.
@ConfigurationAnnotation(predix="dev")
public class MyDevApplicationProperties {
private STring name;
private int port;
private String dbname;
private String dbuser;
private String dbpassword;
// getter와 setter 메소드
}
여기서, 스프링은 프로퍼티 파일에서 'dev'로 시작하고 MyDevAppProperties 클래스의 필드와 동일한 이름을 가진 프로퍼티를 자동으로 바인딩할 것이다.
다음으로, @EnableConfigurationProperties 어노테이션을 사용하여 @Configuration 클래스 내의 @ConfigurationProperties 빈을 등록한다.
@Configuration
@EnableConfigurationProperties(MyDevAppProperties.class)
public class MySpringBootDevApp {}
마지막으로 프로퍼티 값을 테스트하기 위한 Test Runner를 만들자.
@Component
public class DevPropertiesTest implements CommandLineRunner {
@Autowired
private MyDevAppProperties devProperties;
@Override
public void run(String... args) throws Exception {
System.out.println("App Name = " + devProperties.getName());
System.out.println("DB Url = " + devProperties.getDburl());
System.out.println("DB User = " + devProperties.getDbuser());
}
}
또한 @Bean 어노테이션이 있는 메소드에 @ConfigurationProperties를 사용할 수도 있다.
@EnableConfigurationProperties
프로젝트의 구성 클래스를 사용하기 위해서, 우리는 스프링 빈으로 등록할 필요가 있다. 그런 경우에 @EnableConfigurationProperties 어노테이션의 도움을 받을 수 있다. 우리는 이 어노테이션을 사용하여 스프링 컨텍스트에서 구성 빈(@Configuration Properties 어노테이션 클래스)을 등록한다. 이것은 @ConfigurationProperties 어노테이션 빈을 빠르게 등록하는 편리한 방법이다. 더욱이, @ConfigurationProperties와 강하게 결합되어 있다. 예를 들면, 이전 장에서 @ConfigurationProperties를 참조할 수 있다.
@EnableConfiguraionPropertiesScan
@EnableConfigurationPropertiesScan 어노테이션은 파라미터 값에 따른 패키지 스캔을 하고 패키지 하위에 @ConfigurationProperties 어노테이션이 있는 모든 클래스를 찾는다.
예를 들어, 아래 코드를 보자
@SpringBootApplication
@EnableConfigurationPropertiesScan("com.dev.spring.test.annotation")
public class MyApplication {}
위의 코드에서, @EnableConfiguraionPropertiesScan*은 "com.dev.spring.test.annotation" 패키지 내에서 *@ConfigurationProperties 어노테이션이 있는 모든 클래스를 스캔할 것이고 그들을 등록할 것이다.
@EntityScan과 @EnableJpaRepositories
@ComponentScan, @ConfigurationPropertiesScan과 같은 스프링 부트 어노테이션과 *@SpringBootApplication은 스캔 위치를 정의하는데 패키지를 사용한다. 유사하게 @EntityScan과 *@EnableJpaRepositories 또한 스캔 위치를 정의하는 데 패키지를 사용한다. 여기서, 우리는 엔터티 클래스를 찾는데 @EntityScan을 사용하는 반면 JPA 리포지토리 클래스를 찾는데 *@EnableJpaRepositories를 사용한다. 이러한 어노테이션은 일반적으로 클래스가 최상위 패키지 내에 없거나 메인 클래스의 서브 클래스에 없을 때 사용된다. @EnableAutoConfiguration은 최상위 패키지의 하위 모든 클래스를 스캔한다. 그러므로 리포지토리 클래스 혹은 엔티티 클래스가 메인 패키지 하위에 없다면, 적절한 패키지가 @EntityScan과 *@EnableJpaRepositories 어노테이션으로 메인 애플리케이션 구성 클래스에 선언되어야 한다. 예를 들면 아래 코드를 보자.
@EntityScan(basePackage = "com.dev.springboot.example.entity")
@EnableJpaRepositories(basePackages = "com.dev.springboot.example.jpa.repositories")