[Spring] Component Scan๊ณผ Function์ ์ฌ์ฉํ ๋น ๋ฑ๋ก ๋ฐฉ๋ฒ
1. @ComponentScan
@ComponentScan ์ ๋ ธํ ์ด์ ์ spring 3.1๋ถํฐ ๋์ ๋์ผ๋ฉฐ ์ค์ ๋ ์์ ์ง์ ๋ถํฐ ์ปดํฌ๋ํธ ํด๋์ค๋ฅผ scanningํ์ฌ ๋น์ผ๋ก ๋ฑ๋กํด์ฃผ๋ ์ญํ ์ ํ๋ค.
์ปดํฌ๋ํธ ํด๋์ค๋ ๋ค์ ์ ๋ ธํ ์ด์ ์ด ๋ถ์ ํด๋์ค๋ฅผ ์๋ฏธํ๋ค.
- @Component
- @Repository
- @Service
- @Controller
- @Configuration
@ComponentScan์ ๊ฐ์ฅ ์ค์ํ ๋ ๊ฐ์ง ์์ฑ์ component๋ฅผ scanํ ์์ ์ง์ ์ ์ค์ ํ๋ ์์ฑ๊ณผ scanํ component ์ค ๋น์ผ๋ก ๋ฑ๋กํ์ง ์์ ํด๋์ค๋ฅผ ์ ์ธํ๋ ํํฐ ์์ฑ์ด๋ค.
1) Scan ์์ ์ง์ ์ค์ - basePackages()์ basePackageClasses()
basePackages()์ basePackageClasses()๋ component๋ฅผ scanํ ์์ ์ง์ ์ ์ค์ ํ๋ ์์ฑ์ด๋ค.
basePackages()์๋ scan์ ์์ํ ํจํค์ง๋ฅผ ๋ฌธ์์ด๋ก ์ง์ ํ๊ณ basePackageClasses()์๋ scan์ ์์ํ ํด๋์ค ํ์ ์ ์ง์ ํ๋ค.
๋ ์ค ํ๋์ ์์ฑ์ ํํ์ฌ scan ์์ ์ง์ ์ ์ค์ ํ๋ฉด ๋๋ค.
์์ ๊ฐ์ด ์ค์ ํ๋ฉด scan ์์ ํจํค์ง๊ฐ com.atoz_develop.demospring51๋ก ์ค์ ๋๋ค.
com.atoz_develop.demospring51 ํจํค์ง์ ํฌํจ๋ ํ์ ํจํค์ง์ ๋ชจ๋ component๋ฅผ scanํด์ ๋น์ผ๋ก ๋ฑ๋กํด์ค๋ค.
์์ ๊ฐ์ด ์ค์ ํ๋ฉด ๋ง์ฐฌ๊ฐ์ง๋ก scan ์์ ํจํค์ง๊ฐ com.atoz_develop.demospring51๋ก ์ค์ ๋๋ค.
TestConfiguration ํด๋์ค๊ฐ ํฌํจ๋ ํจํค์ง๊ฐ ์์ ํจํค์ง๊ฐ ๋๋ค.
๋ ์ค basePackageClasses()๋ก ์ค์ ํ๋ ๊ฒ์ด ๋ type safeํ ๋ฐฉ๋ฒ์ด๋ค.
basePackages()๋ basePackageClasses()๋ฅผ ์ค์ ํด์ฃผ์ง ์์ผ๋ฉด ๊ธฐ๋ณธ์ ์ผ๋ก @ComponentScan์ด ๋ถ์ด์๋ configuration ํด๋์ค๊ฐ ์๋์ผ๋ก ์์ ์ง์ ์ด ๋๋ค.
๋ฐ๋ผ์ ์ ์ธ ๊ฐ์ง ์์ ๋ ๋ชจ๋ scan ์์ ์ง์ ์ด ๋์ผํ๋ฉฐ out ํจํค์ง์ ์๋ ํด๋์ค๋ scan ๋์์ด ์๋๊ฒ ๋๋ค.
2) ๋น ํํฐ๋ง - excludeFilters
Component scan์ ํตํด ๋น์ ๋ฑ๋กํ ๋ execludeFilters ์์ฑ์ ์ฌ์ฉํด์ ํน์ ๋น์ ๋ฑ๋ก๋์ง ์๋๋ก ์ค์ ํ ์ ์๋ค. ์ค์ ๋ฐฉ๋ฒ์ ๋ค์ํ๋ฉฐ ๋ค์์ ์ ๋ ธํ ์ด์ ์ ์ด์ฉํด์ ํํฐ๋งํ๋ ๋ฐฉ๋ฒ์ด๋ค.
IgnoreDuringScan ์ ๋ ธํ ์ด์ ์ ์๋ก ์ ์ํ๋ค.
์ด ์ ๋ ธํ ์ด์ ์ด ๋ถ์ ์ปดํฌ๋ํธ๋ ํํฐ๋งํ์ฌ ๋น์ผ๋ก ๋ฑ๋กํ์ง ์์ ๊ฒ์ด๋ค.
1
2
3
4
5
6
7
8
9
|
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface IgnoreDuringScan {
}
|
cs |
ํํฐ๋งํ ์ปดํฌ๋ํธ ํด๋์ค์ @IgnoreDuringScan ์ ๋ ธํ ์ด์ ์ ๋ถ์ธ๋ค.
1
2
3
4
5
6
|
import org.springframework.stereotype.Service;
@Service
@IgnoreDuringScan
public class AnotherBookService {
}
|
cs |
@Service ์ ๋ ธํ ์ด์ ์ด ๋ถ์ด์์ผ๋ฏ๋ก ๊ธฐ๋ณธ์ ์ผ๋ก ํํฐ๋ง ์ค์ ์ด ์์ผ๋ฉด ์ด ํด๋์ค๋ ๋น์ผ๋ก ๋ฑ๋ก๋๋ค.
Configuration์ ํํฐ ์ค์ ์ ์ถ๊ฐํ๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.ComponentScan.Filter;
@Configuration
@ComponentScan(
basePackageClasses = ApplicationConfig.class,
excludeFilters = @Filter(
type = FilterType.ANNOTATION,
classes = {IgnoreDuringScan.class}
)
)
public class ApplicationConfig {
}
|
cs |
excludeFilters ์์ฑ์ ์ฌ์ฉํด @IgnoreDuringScan ์ ๋ ธํ ์ด์ ์ด ๋ถ์ด์๋ ์ปดํฌ๋ํธ ํด๋์ค๋ ๋น์ผ๋ก ๋ฑ๋กํ์ง ์๋๋ก ํ๋ค.
์ค์ ํ ๋๋ก AnotherBookService๊ฐ ๋น์ผ๋ก ๋ฑ๋ก๋์ง ์์๋์ง ํ์ธํด๋ณด๊ธฐ ์ํด Application ํด๋์ค์์ ์ถ๋ ฅํด๋ณด์.
1
2
3
4
5
6
7
8
9
10
11
12
|
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import java.util.Arrays;
public class Demospring52Application {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfig.class);
System.out.println(context.containsBean("anotherBookService"));
}
}
|
cs |
ApplicationContext์ containsBean()์ ์ง์ ํ ๋น์ด IoC์ ๋ฑ๋ก๋ผ์๋์ง ์ฌ๋ถ๋ฅผ ๋ฆฌํดํ๋ค.
์คํ ๊ฒฐ๊ณผ
2. Function์ ์ฌ์ฉํ ๋น ๋ฑ๋ก ๋ฐฉ๋ฒ
Function์ ์ฌ์ฉํด์ ๋น์ ๋ฑ๋กํ๋ ๋ฐฉ๋ฒ์ spring 5๋ถํฐ ์ถ๊ฐ๋์๋ค.
๋น ๋ฑ๋ก ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ๋ค.
Spring boot ์ดํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ๋ํ๋ ๋ฐฉ๋ฒ์๋ SpringApplication.run()๊ณผ ๊ฐ์ด static ๋ฉ์๋๋ฅผ ํธ์ถํ๋ ๋ฐฉ๋ฒ ์ธ์ ์ธ์คํด์ค๋ฅผ ์์ฑํด์ ๊ตฌ๋ํ๋ ๋ฐฉ๋ฒ์ด ์๋ค.
Application ํด๋์ค๋ฅผ ๋ค์๊ณผ ๊ฐ์ด ์์ ํ๋ค.
Local ๋ณ์ var๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์๋ JDK 10 ์ด์์ด ํ์ํ๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Demospring52Application {
public static void main(String[] args) {
// SpringApplication.run(Demospring52Application.class, args);
var app = new SpringApplication(Demospring52Application.class);
// ์ฌ๊ธฐ์ ๋น ๋ฑ๋ก ์ฝ๋ ์์ฑ
app.run(args);
}
}
|
cs |
๊ธฐ์กด์ run() ํธ์ถ๋ถ๋ฅผ ์ฃผ์์ฒ๋ฆฌํ๊ณ SpringApplication ์ธ์คํด์ค๋ฅผ ์์ฑํด์ run()์ ํธ์ถํ๋ค.
SpringApplication ์ธ์คํด์ค ์์ฑ๊ณผ run() ํธ์ถ ์ฌ์ด์ ๋น์ ๋ฑ๋กํ๋ ์ฝ๋๋ฅผ ๋ค์๊ณผ ๊ฐ์ด ์์ฑํด์ฃผ๋ฉด ๋๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.support.GenericApplicationContext;
import out.MyService;
@SpringBootApplication
public class Demospring52Application {
@Autowired
MyService myService;
public static void main(String[] args) {
// SpringApplication.run(Demospring52Application.class, args);
var app = new SpringApplication(Demospring52Application.class);
app.addInitializers(new ApplicationContextInitializer<GenericApplicationContext>() { // GenericApplicationContext๋ก ์ค์
@Override
public void initialize(GenericApplicationContext ctx) {
ctx.registerBean(MyService.class);
}
});
app.run(args);
}
}
|
cs |
ctx.registerBean()์ด ๋น์ ๋ฑ๋กํ๋ ๋ถ๋ถ์ด๋ค.
@ComponentScan์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ๊ณผ ๋ฌ๋ฆฌ function์ ์ฌ์ฉํ ๋น ๋ฑ๋ก ๋ฐฉ๋ฒ์ ์ค์บ ๋ฒ์์ ๊ตฌ์ ๋ฐ์ง ์๋๋ค.
MyService๋ Application ํด๋์ค์ ๋ค๋ฅธ ํจํค์ง์ ์์ผ๋ฉฐ @Component ์ ๋ ธํ ์ด์ ์ด ๋ถ์ด์์ง ์์ ํด๋์ค์ด๋ค.
์ด ํด๋์ค๋ฅผ ctx.register()๋ฅผ ์ด์ฉํด ๋น์ผ๋ก ๋ฑ๋กํ๊ณ ์ ์์ ์ผ๋ก ๋ฑ๋ก๋๋์ง ํ์ธํด๋ณด๊ธฐ ์ํด @Autowired๋ก ํ๋์ ์ฃผ์ ๋ฐ์๋ค.
์คํ ๊ฒฐ๊ณผ
์์ ๊ฐ์ด ์ดํ๋ฆฌ์ผ์ด์ ์ด ์ ์์ ์ผ๋ก ์คํ๋๋ ๊ฒ์ผ๋ก ๋น์ด ์ ๋ฑ๋ก๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
์ด ์ฝ๋๋ ๋๋ค์์ ์ด์ฉํด์ ์งง๊ฒ ํํํ ์ ์๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.support.GenericApplicationContext;
import out.MyService;
@SpringBootApplication
public class Demospring52Application {
@Autowired
MyService myService;
public static void main(String[] args) {
var app = new SpringApplication(Demospring52Application.class);
/*app.addInitializers(new ApplicationContextInitializer<GenericApplicationContext>() { // GenericApplicationContext๋ก ์ค์
@Override
public void initialize(GenericApplicationContext ctx) {
ctx.registerBean(MyService.class);
}
});*/
// Lambda ~
app.addInitializers((ApplicationContextInitializer<GenericApplicationContext>) ctx -> ctx.registerBean(MyService.class));
app.run(args);
}
}
|
cs |
์ฐธ๊ณ ๋ก registerBean()์ ์ด์ฉํด์ ๋ค์๊ณผ ๊ฐ์ด ApplicationRunner๋ฅผ ๋น์ผ๋ก ๋ฑ๋กํ ์๋ ์๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.support.GenericApplicationContext;
import out.MyService;
import java.util.function.Supplier;
@SpringBootApplication
public class Demospring52Application {
@Autowired
MyService myService;
public static void main(String[] args) {
var app = new SpringApplication(Demospring52Application.class);
app.addInitializers((ApplicationContextInitializer<GenericApplicationContext>) ctx -> {
ctx.registerBean(MyService.class);
// ๋ฉ์์ง๋ฅผ ์ถ๋ ฅํ๋ ApplicationRunner๋ฅผ ์์ฑํด์ ๋น์ผ๋ก ๋ฑ๋ก
ctx.registerBean(ApplicationRunner.class, new Supplier<ApplicationRunner>() {
@Override
public ApplicationRunner get() {
return new ApplicationRunner() {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("Hello World!!");
}
};
}
});
});
app.run(args);
}
}
|
cs |
registerBean()์ ์ฒซ ๋ฒ์งธ ํ๋ผ๋ฏธํฐ๋ก ApplicationRunner์ ํ์ ์ ์ ๋ฌํ๊ณ ํจ์ํ ์ธํฐํ์ด์ค Supplier๋ฅผ ์ด์ฉํด์ ๋ ๋ฒ์งธ ํ๋ผ๋ฏธํฐ๋ก ApplicationRunner ํ์ ์ ์ธ์คํด์ค๋ฅผ ์ ๊ณตํด์ค๋ค.
๊ฐ๋จํ๊ฒ "Hello World!!"๋ฅผ ์ถ๋ ฅํ๋ ApplicationRunner๋ฅผ ๋ง๋ค์ด์ ๋น์ผ๋ก ๋ฑ๋กํ๋ ์ฝ๋์ด๋ค.
์คํ ๊ฒฐ๊ณผ
๋ง์ฐฌ๊ฐ์ง๋ก lambda์์ผ๋ก ์งง๊ฒ ํํํ ์ ์๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.support.GenericApplicationContext;
import out.MyService;
@SpringBootApplication
public class Demospring52Application {
@Autowired
MyService myService;
public static void main(String[] args) {
var app = new SpringApplication(Demospring52Application.class);
app.addInitializers((ApplicationContextInitializer<GenericApplicationContext>) ctx -> {
ctx.registerBean(MyService.class);
// ๋ฉ์์ง๋ฅผ ์ถ๋ ฅํ๋ ApplicationRunner๋ฅผ ์์ฑํด์ ๋น์ผ๋ก ๋ฑ๋ก
ctx.registerBean(ApplicationRunner.class, () -> args1 -> System.out.println("Hello World!!"));
});
app.run(args);
}
}
|
cs |
3. Component Scanning VS Functional
@ComponentScan ๋ฐฉ์์ ์ฑ๊ธํค scope์ธ ๋น๋ค์ ๋ชจ๋ ์ด๊ธฐ์ ์์ฑํ๋ค.
๋ฐ๋ผ์ ๋ฑ๋กํด์ผํ ๋น์ด ๋ง์ ๊ฒฝ์ฐ ์ดํ๋ฆฌ์ผ์ด์ ์ ์ด๊ธฐ ๊ตฌ๋์๊ฐ์ด ์ค๋ ๊ฑธ๋ฆด ์ ์๋ค๋ ๋จ์ ์ด ์๋ค.
Function์ ์ฌ์ฉํ ๋น ๋ฑ๋ก ๋ฐฉ๋ฒ์ @ComponentScan์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ๋ณด๋ค ์ดํ๋ฆฌ์ผ์ด์ ์ด๊ธฐ ๊ตฌ๋ ์๊ฐ์ด ๋ ์งง๋ค.
๋ ๋ค๋ฅธ ์ฅ์ ์ ์กฐ๊ฑด์ ๋ฐ๋ผ ๋น์ ๋ฑ๋กํ๋ค๋์ง ํ๋ ๋ก์ง์ ์ถ๊ฐํ ์ ์๋ค๋ ๊ฒ์ด๋ค.
์ฆ ๋น์ ๋ฑ๋กํ๋๋ฐ ์์ด์ ํ๋ก๊ทธ๋๋ฐ์ ์ธ ์ปจํธ๋กค์ด ๊ฐ๋ฅํด์ง๋ค.
๋ ๋ฐฉ๋ฒ ์ค ํ๋๋ฅผ ๋ฐ๋์ ํํด์ผ ํ๋๊ฑด ์๋๊ณ ๋ ๋ค ๋์์ ์ฌ์ฉํ ์ ์๋ค.
์ด ๊ฒฝ์ฐ @ComponentScan ๋ฐฉ์์ ๋น์ด ๋จผ์ ๋ฑ๋ก๋๋ค.
@ComponentScan์ BeanFactoryPostProcessor๋ฅผ ๊ตฌํํ ConfigurationPostProcessor์ ์ฐ๊ด์ด ๋ผ์๋ค.
BeanFactoryPostProcessor์ ๊ตฌํ์ฒด๋ค์ ๋ค๋ฅธ ๋ชจ๋ ๋น๋ค์ ๋ง๋ค๊ธฐ ์ด์ ์ ์ ์ฉ๋๋ค.
์ฆ ๋ค๋ฅธ ๋น๋ค์ ๋ฑ๋กํ๊ธฐ ์ ์ @ComponentScan์ผ๋ก ๋น์ ๋จผ์ ๋ฑ๋กํ๋ค.
์ฌ๊ธฐ์ ๋ค๋ฅธ ๋น๋ค์ด๋ @Bean ๋๋ function์ ์ฌ์ฉํด์ ์ง์ ๋ฑ๋กํ ๋น์ ๋งํ๋ค.
Functionalํ ๋น ๋ฑ๋ก์ ๋ชจ๋ ๋น์ ์ง์ ๋ฑ๋กํด์ค์ผ ํ๊ธฐ ๋๋ฌธ์ ๋ฒ๊ฑฐ๋กญ๊ณ ์ฝ๋๊ฐ ๋ณต์กํด์ง๋ค.
๋ฐ๋ผ์ @ComponentScan ๋ฐฉ์์ ์์ ํ ๋์ฒดํด์ ์ฌ์ฉํ๊ธฐ ๋ณด๋ค๋ @ComponentScan์ผ๋ก ๋ฑ๋กํ๋ ๋น ์ธ์ @Bean์ผ๋ก ์ง์ ๋ฑ๋กํด์ผํ๋ ๋น์ด ์์ ๊ฒฝ์ฐ functionalํ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๋ ๊ฒ์ ๊ณ ๋ คํด๋ณด๋๊ฒ ์ข๋ค.
References
์ธํ๋ฐ - ๋ฐฑ๊ธฐ์ ๋์ ์คํ๋ง ํ๋ ์์ํฌ ํต์ฌ ๊ธฐ์
'Spring' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Spring] EnvironmentCapable - Profile ์ฌ์ฉํ๊ธฐ (0) | 2020.03.04 |
---|---|
[Spring] ๋น์ Scope - ์ฑ๊ธํค๊ณผ ํ๋กํ ํ์ (0) | 2020.03.03 |
[Spring] @Autowired ๋์ ์๋ฆฌ - BeanPostProcessor (0) | 2020.03.01 |
[Spring] @Autowired์ ๋ค์ํ ์ฌ์ฉ ๋ฐฉ๋ฒ - required, Primary, Qualifier (0) | 2020.03.01 |
[Spring] ๋น์ ์ค์ ํ๋ 3๊ฐ์ง ๋ฐฉ๋ฒ - XML, JAVA, Component Scan (0) | 2020.03.01 |
๋๊ธ