kenzi
컨테이너와 빈 방식에 관하여 본문
스프링에서 컨테이너란 무엇인가?
Container는 자바 객체를 관리하는 객체간의 연관관계를 생성하는 역할
여기서 자바 객체를 Bean이라고 한다
왜 Container를 사용하는가?
제어의 흐름을 외부에서 관리하기 위해서
왜 제어의 흐름을 외부에서 관리해야하는데?
객체를 재사용하기 쉽고 유지보수를 용이하게 하기 위해서
클래스에서 매번 객체를 생성하여 사용했을 시 객체가 추가되거나 수정되어야 하는 상황이 일어났을때 클래스마다 쫓아가서 수정해야하는 일이 발생 = 너무 번거로움
객체를 외부에서 주입시켜주는 방식이라면 클래스마다 쫓아가지 않아도 주입할때 다른 것을 주입시켜주면 수정이 가능
예시) 회사마다 다른 자소서를 쓸 때 지원회사이름을 눈빠지게 찾아서 수정하지 않아도 한번 수정하면 다같이 수정되는 그런 느낌적인 느낌....예시가 이게 맞나...
Container 안에 Bean 넣는 방법
1) xml에 <bean id ="~" class = "~"/> 태그로 넣고
//Container1.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns = "http://www.springframework.org/schema/beans"
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id = "greeter" class = "ch02_obj.Greeter">
<property name ="format" value = "안녕하세요 스프링 첫날입니다">
</property>
</bean>
<bean id = "pwChangeSvc" class = "ch02_obj.PasswordChangeService">
<constructor-arg>
<ref bean = "userRepository"></ref>
</constructor-arg>
</bean>
</beans>
1-1) Main에서
GenericXmlApplicationContext로 빈 팩토리를 만들고 .getBean(bean의 id, class)로 bean을 불러오기
GenericXmlApplicationContext factory
= new GenericXmlApplicationContext("classpath:ch02_DIXML/Container1.xml");
Greeter g1 = factory.getBean("greeter", Greeter.class);
//getBean하는 방식 중에 이런 방식도 있습니다
PasswordChangeService pcw = (PasswordChangeService) factory.getBean("pwChangeSvc");
2) xml에서 <context:component-scan base-package="패키지명"/> 을 사용하고 - 왜? 매번 xml등록하기 번거로워..
//Container4_scan.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns = "http://www.springframework.org/schema/beans"
xmlns:context = "http://www.springframework.org/schema/context"
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- scan으로 패키지에 있는 bean을 가져오겟다 -->
<context:component-scan base-package="ch02_objScan"/>
<bean id = "user1" class = "ch02_obj.User">
<constructor-arg value = "kicuser"></constructor-arg>
<constructor-arg value = "1111"></constructor-arg>
</bean>
<bean id = "user2" class = "ch02_obj.User">
<constructor-arg value = "kicstu"></constructor-arg>
<constructor-arg value = "1234"></constructor-arg>
</bean>
<bean id = "authFailLogger" class = "ch02_obj.AuthFailLogger">
<property name = "threshold" value = "2" />
</bean>
</beans>
2-1) 스캔할 패키지에 있는 클래스들에 @Component 사용
@Autowired란 xml에서 의존성 주입을 해주었던 참조객체들을 표시해줘야하니까
AuthenticationService는 UserRepository와 AuthFailLogger에 의존(참조)하고 있었거든
//AuthenticationService.java
@Component //이 클래스가 Bean이 될거야
public class AuthenticationService {
@Autowired //프로퍼티를 자동으로 연결해줍니다
UserRepository userRepository;
@Autowired
AuthFailLogger authFailLogger;
/*
Aurowired에 의해 자동으로 연결해주니까 이 과정이 필요없습니다
//setter injection 방식
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
//setter injection 방식
public void setAuthFailLogger(AuthFailLogger authFailLogger) {
this.authFailLogger = authFailLogger;
}
*/
}
xml에 있었다면 이런 bean태그가 아래와 같이 있었을 것이다...
<bean id = "authenticationService" class ="ch02_obj.AuthenticationService">
<property name = "userRepository" ref = "userRepository" />
<property name = "authFailLogger" ref = "authFailLogger"/>
</bean>
//PasswordChangeService.java
@Component("pwChangeSvc")
public class PasswordChangeService {
UserRepository userRepository;
@Autowired
public PasswordChangeService(UserRepository userRepository) {
this.userRepository = userRepository;
}
}
이것 역시 xml에 있었다면 아래와 같이 있었을 것이다..
<bean id = "pwChangeSvc" class = "ch02_obj.PasswordChangeService">
<constructor-arg>
<ref bean = "userRepository"></ref>
</constructor-arg>
</bean>
//UserRepository.java
@Component
public class UserRepository {
//<property name = "users"> : setter injection
private Map<String, User> map = new HashMap<>();
@Autowired
public void setUsers(List<User> li) {
for(User u : li) {
map.put(u.getId(), u);
System.out.println(u);
}
}
}
이것 역시 xml에 있었다면? 아래와 같이!
<bean id = "userRepository" class = "ch02_obj.UserRepository">
<property name = "users">
<list>
<ref bean = "user1" />
<ref bean = "user2" />
</list>
</property>
</bean>
즉 xml에서 bean태그로 안 걸고 component-scan으로 클래스를 bean으로 스캔해달라~
Bean으로 스캔할 클래스가 어떤건지 어떻게 알아?
----> @Component 걸어줄게~~~~~~
Q) 그럼 property는 어떻게 알아? xml에서는 property 명시해줬는데 클래스에서는 어떻게 알아?
@Autowired 걸어줄게~~~~
Q) @Autowired는 어디에 아무렇게나 걸어?
1) 필드 2) 메서드 3) 생성자에 걸 수 있다!
한 클래스에서 동시다발적으로 걸 수 없고 하나만 선택해서 걸어야 한다
@Autowired는 굴비처럼 줄줄이 엮는것
Q) 그럼 xml에 component-scan하고 나머지 Bean객체 모두 scan할 패키지에 넣고 @Component사용하면 되는데
왜 어떤 객체(user1,user2...)는 xml에 <bean/>태그를 사용해?
value 자체를 정해서 넣어준 객체는 Component로 따로 빼놓을 시 수정,관리가 번거로움
3) xml 없이 컨테이너 만들어서 Bean 등록하기
자바클래스에서 @Configuration으로 여기가 Container다 알려주기
Bean은 @Bean으로 등록하겠다...!
여기서 의존성주입은 set메서드 바로 쓰거나 생성자 넣어버림으로서 해결
//Container3_Anno.java
@Configuration
public class Container3_Anno {
@Bean
//public xml에서의 class, id ()
public User user1() {
return new User("kicuser","1111");
}
@Bean
public User user2() {
return new User("kicstu","1234");
}
@Bean
public AuthenticationService authenticationService() {
AuthenticationService a = new AuthenticationService();
a.setUserRepository(userRepository());
a.setAuthFailLogger(authFailLogger());
return a;
}
@Bean
public UserRepository userRepository() {
UserRepository u = new UserRepository();
u.setUsers(Arrays.asList(user1(),user2()));
return u;
}
@Bean
public AuthFailLogger authFailLogger() {
AuthFailLogger auth = new AuthFailLogger();
auth.setThreshold(2);
return auth;
}
@Bean("pwChangeSvc")
public PasswordChangeService pwChangeSvc() {
return new PasswordChangeService(userRepository());
}
} //end class
3-1) Main에서는
AnnotationConfigApplicationContext 로 빈 팩토리 만들어서 .getBean하기
//Main.java
AnnotationConfigApplicationContext factory
= new AnnotationConfigApplicationContext(Container3_Anno.class);
//getBean하는 방식 중에 이런 방식도 있습니다
PasswordChangeService pcw = (PasswordChangeService) factory.getBean("pwChangeSvc");
정리하자면 컨테이너를 만드는 방식은 2가지가 있음
1) GenericXmlApplicationContext : xml방식
2) AnnotationConfigApplicationContext : Annotation 방식
Bean을 등록하는 방식은 3가지가 있음
1) xml에서 bean태그 사용
2) @Component 사용 (xml에서 component-scan을 쓸때에)--->이때 @Autowired 사용
3) @Bean 사용
'Spring' 카테고리의 다른 글
스프링 4일차 정리 (0) | 2022.03.31 |
---|---|
스프링은 3가지로 끝난다 (0) | 2022.03.31 |
스프링 3일차 (0) | 2022.03.30 |
스프링 2일 (0) | 2022.03.29 |
스프링 기초 복습 ( feat 빈 설정방법) (0) | 2022.03.28 |