filter(상위/하위 컨텍스트)
상위 컨텍스트(웹 관련 없는 것, root) / 하위 컨텍스트 (웹 관련된 것들, child)
<context:component-scan base-package="kr.or.ddit.sample" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
메타 어노테이션을 포함시키고 빼고싶은 것을 뺀다.
service, repository의 메타 어노테이션 component로 되어있다.
public static void main(String[] args) {
try(
ConfigurableApplicationContext rootContext =
new ClassPathXmlApplicationContext("kr/or/ddit/sample/hierarchy/conf/root-context.xml");
ConfigurableApplicationContext childContext =
new ClassPathXmlApplicationContext(new String[] {
"kr/or/ddit/sample/hierarchy/conf/child-context.xml"
}, rootContext);
){
rootContext.registerShutdownHook();
childContext.registerShutdownHook();
//자식에서 부모 가능
SampleService service = childContext.getBean(SampleService.class);
log.info("child 로부터 주입된 service 객체 : {}", service);
//부모에서 자식은 불가능 오류.
SampleController controller = rootContext.getBean(SampleController.class);
}
}
properties파일도 해보자
dbInfo 라는 properties 파일을 읽어야한다.
xmlns:util="http://www.springframework.org/schema/util" 이것도 추가했다.
convention over configuration (CoC) >> 리스트 기본은 ArrayList.
<util:list id="sampleList" list-class="java.util.LinkedList">
<value>element1</value>
<bean class="java.util.Date" />
</util:list>
사이즈가 미리 채워진채로 컬렉션을 만들어야하기 때문에 utils 네임스페이스를 추가하고 사용하려고 한다.
컬렉션을 만들고 컬렉션을 미리 초기화 시켜준다는 장점이 있다.
properties파일의 특징 : 휘발성이 아니다. 파일로 저장된다. > location이라는 속성을 갖는다.
<util:properties id="dbInfo" location="classpath:kr/or/ddit/db/dbinfo.properties">
<prop key="prop1">VALUE1</prop>
<prop key="prop2">VALUE2</prop>
</util:properties>
<bean class="kr.or.ddit.properties.obj.DBInfo"
p:driverClassName="#{dbInfo.driverClassName}"
p:url="#{dbInfo['url']}"
p:username="#{dbInfo['username']}"
p:password="#{dbInfo['password']}"
p:initialSize="#{dbInfo['initialSize']}"
p:maxTotal="#{dbInfo['maxTotal']}"
p:maxWait="#{dbInfo.maxWait}"
/>
EL 표현식이 가능한데, 표현법이 조금 다르다. $ 대신 #
그리고 연산배열구조(ㅋㅋㅋ[ ' ㅋㅋㅋ ' ])가 가능하다. 닷노테이션(ㅋㅋㅋ.ㅋㅋㅋ) 가능하다
p:initialSize="#{dbInfo['initialSize'] + 4}"
jsp에서는 2 + 4 = 6 으로 나온다.( 강제로 파싱한 결과) 그러나 Spring에서는>> 컨켓연산하여 24 로 나온다.
p:maxTotal="#{dbInfo['maxTotal'] * 3}"
jsp에서는 *3 하면 곱하기 3이지만 Spring에서는>> 2를 3배로 늘려서 2, 2, 2하여 결과는 222로 나온다.
properties 파일 읽어들이는 방법 2
<context:property-placeholder/> : bean이 등록되는 것이 아니다.
커다란 그릇에 프로퍼티들이 담겨있어 그걸 프로퍼티 소스라고 해
이것에서 코드어시스트 받아보면 로케이션 있어. 밑에서는 그걸로 프로퍼티스를 읽어서 객체로 만들었는데
여기서는 객체로 만들지 않고 이 안에다가 싹 다 넣어주는 것이야.
<context:property-placeholder location="classpath:kr/or/ddit/db/dbinfo.properties"/>
<bean id="vo2" class="kr.or.ddit.properties.obj.DBInfo"
p:driverClassName="${p:driverClassName}"
/>
이건 플레이스홀더야 여기에는 빈의 아이디가 아닌 프로퍼티네임 그대로 들어가
수동으로 등록하지 않는 상황을 만들어보자.
▶Properties-Read-auto.xml
<context:component-scan base-package="kr.or.ddit.properties.obj" />
<util:properties id="dbInfo" location="classpath:kr/or/ddit/db/dbinfo.properties">
<prop key="prop1">VALUE1</prop>
<prop key="prop2">VALUE2</prop>
</util:properties>
▶DBInfo
@Component
@Data //setter가 생김. -> setterInjection 가능
public class DBInfo {
// @Inject //의미상 맞지가 않아... 특정 프로퍼티의 값을 넣어야해서. 프로퍼티자체가 아니라.
// @Value("${driverClassName}")
@Value("#{dbInfo.driverClassName}")
private String driverClassName;
@Value("#{dbInfo.url}")
private String url;
@Value("#{dbInfo.user}")
private String username;
@Value("#{dbInfo.password}")
private String password;
@Value("#{dbInfo.initialSize}")
private int initialSize;
@Value("#{dbInfo.maxTotal}")
private int maxTotal;
@Value("#{dbInfo.maxWait}")
private long maxWait;
}
자바 컨테이너방식으로 컨피그 설정하기
@Configuration //beans
@Lazy
@ComponentScan(basePackages = "kr.or.ddit.container.obj", useDefaultFilters = true)
public class JavaConfigContainerConfiguration {
// @Bean //메서드 이름이 bean id, 싱글턴
// public Bar bar1() {
// return new Bar();
// }
//
// @Bean //메서드 이름이 bean id, 싱글턴
// public Bar bar2() {
// return new Bar();
// }
//
// @Bean
// public Baz baz() {
// return new Baz();
// }
//컴포넌트 설정에 필요한 베이스 패키지가 없어서 실행되지 않는다.
//어노테이션이 있어도 베이스 패키지 등록이 없다면 실행 오류.
@Bean
@Scope("prototype")
public Foo foo(@Autowired @Qualifier("bar") Bar bar, Baz baz) {
Foo foo = new Foo(bar);
foo.setBaz(baz);
return foo;
}
}
어노테이션 기반의 이벤트 리스너
버튼을 : 이벤트 타겟
클릭하면 : 이벤트 종류
alert 메세지 : 이벤트 핸들러
>> 마지막 : 이벤트 타겟과 이벤트 핸들러 연결
<<컨테이너가 구동되면 로그메세지 출력!>>
컨테이너 : 이벤트 타겟
구동되면 : 이벤트 종류
로그메세지 출력 : 이벤트 핸들러
>>마지막 : 이벤트 타겟과 이벤트 핸들러 연결
@Slf4j
@Component //애매한 객체에게 사용. 핸들러와 타겟을 연결
public class CustomEventListener {
@EventListener(ContextRefreshedEvent.class) //이 핸들러는 이 이벤트만 처리할거야.
public void eventHandler(ContextRefreshedEvent event) {
log.info("============ 컨텍스트 로딩 완료! =============");
}
}
/**
* 이벤트 처리 단계
* 1. 이벤트 타겟 결정
* 2. 처리할 이벤트 종류 결정
* 3. 이벤트 처리 핸들러 구현
* 4. 이벤트 타겟과 핸들러를 연결.
* let handle = function(event){ //핸들러는 이벤트를 받는다.
* alert("메시지" + event.target); //모든 핸들러는 타겟에 대한 레퍼런스를 갖는다.
* }
* ${"button").on("click", handler);
* //컨테이너가 구동이되면 로그메세지 출력
*/
public class SpringEventHandlerDesc {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(JavaConfigContainerConfiguration.class);
context.registerShutdownHook();
}
}
Web Application 한정으로 쓸 수 있는 Context가 있다.
아직 우리는 등록해두지 않았다.
등록하자.
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${org.springframework-version}</version>
</dependency>
web용 컨테이너 설정해야한다.
DS HM HA VR - spring-webmvc
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
web.xml
ContextLoaderListener implements ServletContextListener
ServletContextListener : Interface for receiving notification events about ServletContext lifecycle changes.
>> 제일먼저 발생한다. >그곳에 container를 시작해야한다. >그것의 리스너가 web.xml에 등록된것이 임플리먼츠하는 것이다.
/**
* Initialize the root web application context.
* // 우리 어플리케이션의 엔트리포인트
* // 맨처음 실행되는 곳
*/
@Override
public void contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());
}
/**
* Close the root web application context.
*/
@Override
public void contextDestroyed(ServletContextEvent event) {
closeWebApplicationContext(event.getServletContext());
ContextCleanupListener.cleanupAttributes(event.getServletContext());
}
<context:component-scan base-package="egovframework">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>
상위 컨테이너
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/config/egovframework/springmvc/dispatcher-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
하위 컨테이너 ㄴ
dummySpring
리스너가 상위 컨테이너를 생성하고 컨텍스트 파람으로 넘기고 있다.
서블릿이 하위 컨테이너를 생성하고 있고 하위 설정파일로 들어가 있다.
1.웹과 상관없거나 2. 기존의 시스템과 연결되어야하는 경우 상위로 빠진다.
<context:component-scan base-package="kr.or.ddit" /> 어노테이션만 붙이면 무조건 다 하위로 들어가도록 하는 설정
분리하려면 선택적인 필터링이 필요하다.
자동으로 등록
<annotation-driven />
명시적으로 등록
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
정적자원 일괄등록
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
톰캣을 살펴보자
톰캣도 어플리케이션이라서 서블릿이 있다. jsp도 서블릿
default 서블릿 등록되어 있다. WS의 정적자원처리를 톰캣이 해주고 있는데 그럴 수 있었던 이유는 default서블릿 덕분이다. 이 default의 url은 "/" 정적자원 담당 url 웬만하면 이 주소로 맵핑걸지 말라고 되어 있다. spring이 이 주소를 가져가버림. 그럼 우리는 정적 자원을 처리할 수 없다. 정적, 동적 요청을 모두 디스패처서블릿이 감당해야한다. 그래서 우리가 감당하지 않기 위해 넘긴것. 정적자원을 담당하는 컨트롤러를 만들지 않아도 된다. "/resources/**" (/** 몇개로 쪼개져도 상관 없다.) requestMapping처럼 트레이싱 할 수 있도록 맵핑의 역할을 한다. 장점 : 일괄처리가 가능하다. cache-period="0"/ 캐시를 남기지 말아라.
컨테이너 계층구조 사용하기
myBatis연동해보기
'내가 보려고 정리하는 > Spring' 카테고리의 다른 글
웹 : datasource-context : 0410 (1) | 2023.04.10 |
---|---|
웹 : 스프링 방식으로 해보자. : 0407 (0) | 2023.04.07 |
웹 : Spring : Annotation기반 : 0406(2) (0) | 2023.04.06 |
웹 : Spring : 컨테이너의 Bean 관리 특성 : 0406 (0) | 2023.04.06 |
웹 : C.L와 M.L간의 결합력을 낮추는 스프링의 컨테이너 구조 : 0404, 0405 (0) | 2023.04.04 |