✅ Bean
: Spring Container가 관리하는 객체
✅ Spring container
: Bean 저장소, Bean을 저장, 관리, 생성/소멸, 연결(@Autoweird)
➊ BeanFactory: Bean을 생성, 연결 등의 기본 기능을 정의
➋ ↪확장 | ApplicationContext
: BeanFactory를 확장해서 여러 추가 기능 정의
AC의 종류 | XML | Java Config |
---|---|---|
non-Web | GenericXmlApplicationContext | AnnotationConfigApplicationContext |
Web | XmlWebApplicationContext | AnnotationConfigWebApplicationContext |
cf. java코드는 컴파일러가 check해주지만 XML은 단순text이기 때문에(validator이 설정한다 하더라도) java가 더 유리
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Processes application requests -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
➊ ContextLoaderListener
(이벤트처리기)를 이용하여 톰캣 시작 시 이벤트 체크
✔️ contextConfigLocation에 설정파일 위치(/root-context.xml)를 이용하여XmlWebApplication()
생성
➡️ Root AC
➋<sevlet>태그 안에는 DispatcherServlet을 서블릿으로 등록
✔️ 초기화하면서 servlet-context.xml 설정 파일을 이용하여 XmlWebApplicationContext()
다시 생성
➡️ Servlet AC
➌ 만들어진 2개의 XmlWebApplicationContext()을 연결
➡️ Root AC가 부모, Servlet AC가 자식
✔️ 자식이 부모 참조, 자식을 먼저 찾고 없으면 그 다음 부모를 찾음
✔️ 모듈 별로 자식을 여러개 둘 수 있음
✔️ 부모: 공통 bean, 웹이랑은 관련없는 non-Web 빈
✔️ 자식: 개별적인 bean, 각 모듈에서 사용하는 빈
@Controller
public class HomeController {
@Autowired
WebApplicationContext servletAC; // Servlet AC
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Locale locale, HttpServletRequest request, Model model) {
// 원래는 request.getServletContext()지만, 컨트롤러는 HttpServlet을 상속받지 않아서 아래와 같이 해야함.
ServletContext sc = request.getSession().getServletContext(); // ApplicationContextFacade
WebApplicationContext rootAC = WebApplicationContextUtils.getWebApplicationContext(sc); // Root AC
System.out.println("webApplicationContext = " + rootAC);
System.out.println("servletAC = " + servletAC);
System.out.println("rootAC.getBeanDefinitionNames() = " + Arrays.toString(rootAC.getBeanDefinitionNames()));
System.out.println("servletAC.getBeanDefinitionNames() = " + Arrays.toString(servletAC.getBeanDefinitionNames()));
System.out.println("rootAC.getBeanDefinitionCount() = " + rootAC.getBeanDefinitionCount());
System.out.println("servletAC.getBeanDefinitionCount() = " + servletAC.getBeanDefinitionCount());
System.out.println("servletAC.getParent()==rootAC = " + (servletAC.getParent() == rootAC)); // servletAC.getParent()==rootAC = true
return "home";
}
}
ApplicationContext
: 모듈을 둘러싼 모든 환경들을 묶어놓은 것ApplicationContext
+ cacheReturn Type | Method | Description |
---|---|---|
int | getBeanDefinitionCount() | 정의된 빈의 개수 반환 |
String[] | getBeanDefinitionCount() | 정의된 빈의 이름을 배열로 반환 |
- | ||
빈 얻기 | ||
getBean(Class<T> requiredType) | 타입으로 빈 검색 Car car2 = (Car) ac.getBean(Car.class); | |
Object | getBean(Class<T> requiredType, Objecct... args) | |
getBean(String name) | 이름으로 빈 검색 Car car = (Car) ac.getBean("car"); | |
getBean(String name, Class<T> requiredType) | ||
getBean(String name, Object... args) | ||
- | ||
빈 존재 유무 확인 | ||
Boolean | containsBean(String name) | "name"의 빈이 존재하는 지 확인 |
Boolean | containsBeanDefinition(String beanName) | 빈의 정의가 포함되어 있는지 확인 |
Boolean | containsLocalBean(String name) | |
Anotation | findAnnotaionOnBean(String beanName, Class annotationType) | 빈에 Annotaion 존재 유무 확인(@Component가 붙어있으면 반환) |
- | ||
타입확인 | ||
Boolean | isPrototype(String name) | 빈이 프로토타입인지 확인 |
isSingleton(String name) | 빈이 싱글톤인지 확인 | |
isTypeMatch(String name, Class<T> typeToMatch) | "name"라는 이름의 빈의 타입이 Class<T>인지 확인 | |
isTypeMatch(String name, ResolvableType typeToMatch) | ||
- | ||
String[] | getAliases(String name) | |
getBeanNamesForAnnotation(Class annotationType) | ||
getBeanNamesFoType(Class type, boolean includeNonSingletons, boolean allowEagerInit) | @Component가 붙은 빈의 이름을 배열로 반환 | |
getBeanNamesFoType(Class type) | Class 또는 그 자손 타입인 빈의 이름을 배열로 반환 | |
getBeanNamesFoType(ResolvableType type) | ||
- | ||
Class | getType(String name) | |
Map | getBeanOfType(Class<T> type) | |
Map | getBeanOfType(Class<T> type, boolean includeNonSingletons, boolean allowEagerInit) |
@Component
@Scope("prototype")
class Door {}
@Component class Engine {}
@Component class TurboEngine extends Engine {}
@Component class SuperEngine extends Engine {}
@Component
class Car {
@Value("red") String color;
@Value("100") int oil;
@Autowired Engine engine;
@Autowired Door[] doors;
}
✅ loC
(Inversion Of flow Control 제어의 역전):
제어의 흐름을 전통적인 방식과 다르게 뒤바꾸는 것(flow Control: if문, for문)
✅ DI
(Dependency Injection 의존성 주입):
사용할 객체를 외부에서 주입받는 것
+) 전략패턴(Strategy Pattern):
✔️ 비슷하지만 다르게 구현되어야하는 행위들을 캡슐화하는 공통 인터페이스를 정의하고, 이를 각각의 클래스에서 실제 행위를 구현하여 동적으로 바꾸도록 하는 패턴
✔️ 객체의 행위를 동적으로 바꾸고 싶은 경우 직접 행위를 수정할 필요없이 전략을 변경하여 행위를 유연하게 확장 가능
인스턴스 변수(iv), setter, 참조형 매개변수를 가진 생성자, 메서드에 적용
❶ 생성자 주입: ✨BEST
✔️ 의존관계에 있는 객체들을 private final로 선언하고, 생성자를 통해 해당 객체들을 주입받도록 함
✔️ 불변하게 설계가능, 누락방지, final 사용
❷ 수정자(setter) 주입: 의존관계에 있는 객체들을 private final로 선언하고, 해당 변수에 대한 Setter 메서드를 생성하고 앞에 @Autowired를 붙여서 사용
❸ 필드 주입: 변수 앞에 @Autowired를 붙여서 사용
✔️ Spring container에서 타입으로 빈을 검색해서 참조 변수에 자동 주입(DI)
✴️ 검색된 빈이 n개이면, 그 중 참조변수와 이름이 일치하느 것을 주입 | SuperEngine
✴️ 주입 대상이 변수일 때, 검색된 빈이 1개 아니면 예외발생(반드시 1개) | SuperEngine
✴️ 주입 대상이 배열일 때, 검색된 빈이 n개라도 예외발생X(0개면 예외발생) | TurboEngine, SuperEngine
✴️ @Autowired(required=fale)일 때, 주입할 빈을 못찾아도 예외 발생X
✔️ Spring container에서 이름으로 빈을 검색해서 참조 변수에 자동 주입(DI)
✔️ 일치하는 이름의 빈이 없으면, 예외 발생
✔️ 빈 이름을 생략하면 참조변수 이름 → 빈의 이름
✔️ <component-scan>로 @Component가 클래스를 자동 검색해서 빈으로 등록
✔️ @Controller
, @Service
, @Repository
, @ControllerAdvice
의 메타 애너테이션(애너테이션 내에 @Component 포함)
✅ @Value 에너테이션을 이용하여 systemPropeties와 systemEnvironment 이용
✴️ @Value(“#{systemProperties[‘user.timezone’]}”)
: 사용자의 시간대_GMT(+9)
✴️ @Value(“#{systemEnvironment[‘PWD’]}”)
: 현재 작업 디렉토리
✅ 등호(=)를 구분자로 key/value를 저장해두면 외부파일로부터 값을 불러올수 있음
✔️ JSR: Java Spec Request
✅ javax.inject-1.jar
: @Inject, @Named, @Qualifier, @Scope, @Singleton
✅ annotations-api.jar
: @Resource, @ManagedBean, @PreDestroy, @PostContruct
스프링(spring 제공) | 표준(Java제공) | 비고 |
---|---|---|
@Autowired | @Inject | @Injectd에는 required 속성X |
@Qualifier | @Qualifier, @Named | 스프링의 @Qualifier와 표준의 @Named 유사 |
- | @Resource | 스프링에는 이름검색 기능 없음 |
@Scope("singletone") | @Singleton | 표준에서의 portotype이 디폴트 |
@Component | @Named, @ManagedBean | 표준에서는 반디시 이름 필요 |
cf. spring의 @Scope와 표준의 @Scope와 다름(@Qualifier도 다른 기능임)
cf. 스프링에는 이름검색 기능이 없어 annotations-api.jar
필요
✅ <property>
를 이용한 초기화: .setter를 이용
✔️ <property>
태그 = setter로 초기화
(두개는 같은 역할을 하므로 <property>
사용 시 별도의 setter 초기화 불필요)
✅ <constructor-arg>
를 이용한 초기화: 생성자를 이용
✔️ 생성자가 있어야만 <constructor-arg>
태그 사용 가능
✅ <list>
, <set>
, <map>
참고) 자바의 정석 | 남궁성과 끝까지 간다