• Advertisement

ContextLoaderListener и DispatcherServlet

Обсуждаются вопросы о Spring инъекции зависимостей, включая XML и конфигурацию основанную на аннотациях

ContextLoaderListener и DispatcherServlet

Postby admin » Wed Jun 22, 2011 9:35 am

Я недавно стал изучать Spring Framework, очень мало документации на русском языке. Меня немного смущает конфигурация Spring, а именно, как ContextLoaderListener и DispatcherServlet загружают бины и как ссылка бинов загружается через ContextLoaderListener через контроллер:

web.xml
Code: Select all
<?xml version="1.0" encoding="iso-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4">
       
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
   
    <context-param>
        <param-name>contextConfigLocation</param-name>      
   <param-value>/WEB-INF/conf/services.xml</param-value> 
   <param-value>/WEB-INF/conf/hibernate-dao.xml</param-value>       
    </context-param>
   
    <servlet>
        <servlet-name>bank</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    </servlet>
   
    <servlet-mapping>
        <servlet-name>bank</servlet-name>
        <url-pattern>*.htm</url-pattern>
    </servlet-mapping>
   
</web-app>


Приложение разбито на контроллер, сервис и dao слои. Я определил контроллер бин в bank-servlet.xml, который загружается через DispatcherServlet:
Code: Select all
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:p="http://www.springframework.org/schema/p"
   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"/>

<bean id="viewResolver"
   class="org.springframework.web.servlet.view.InternalResourceViewResolver"
   p:prefix="/WEB-INF/jsp/" p:suffix=".jsp">
</bean>
   <bean id="accountController"   
class="com.bank.web.controller.AccountController"/>
</beans>


Я хотел сослаться здесь на сервисный класс, но прочел, что не рекомендуется использовать здесь средний слой компонентов.
Code: Select all
DispatcherServlet всегда загружает свой конфигурационный файл используя <servlet_name>-servlet.xml. Предполагается, что этот файл будет содержать web компоненты такие как Controllers, ViewResolvers и LocaleResolvers, но не средний слой компонентов.

ContextLoaderListener используется для загрузки среднего слоя и слоя данных. Spring будет объединять все эти компоненты в ApplicationContext, делая средний слой компонентов доступным из web слоя компонентов.



В моем services.xml у меня есть ссылки на hibernate-dao.xml:

services.xml
Code: Select all
<?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 name="accountService" class="com.bank.service.AccountServiceImpl">
    <property name="accountDAO" ref="accountDAO" />
</bean>

<bean name="accountDAO" class="com.bank.domain.dao.spring.AccountHiberDAOImpl">

</bean>

</beans>


и в hibernate-dao.xml ссылки на Session factory, transactionManager итп.:

hibernate-dao.xml
Code: Select all
<?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="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="com.ibm.db2.jcc.DB2Driver" />
        <property name="url" value="jdbc:db2:bank" />
        <property name="username" value="db2admin" />
        <property name="password" value="damobamo" />
    </bean>
<!-- Hibernate SessionFactory -->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="mappingResources">
            <list>
                <value>com/bank/domain/model/Account.hbm.xml</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.DB2Dialect</prop>
                <prop key="hibernate.hbm2ddl.auto">create</prop>
                <prop key="hibernate.jdbc.use_get_generated_keys">false</prop>
            </props>
        </property>
    </bean>
<!-- Transaction manager for a single Hibernate SessionFactory (alternative to JTA) -->
    <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager" autowire="byType">
        <!-- property name="sessionFactory" ref="sessionFactory" /-->
    </bean>
    <bean id="accountDAO" class="com.bank.domain.dao.spring.AccountHiberDAOImpl" autowire="byType">
        <!-- property name="sessionFactory" ref="sessionFactory" /-->
    </bean>
</beans>



Я не понимаю, как мне их объединить, а частности, как ссылаться на сервисный слой из контроллеров.
Я хочу получить доступ к сервисному слою из контроллера.

У меня получилось раздобыть ссылки на сервисные бины.
Code: Select all
protected ModelAndView handleRequestInternal(HttpServletRequest request,
         HttpServletResponse response) throws Exception {
...
AccountHiberDAOImpl accountDAO = (AccountHiberDAOImpl) getApplicationContext().getParent().getBean("accountDAO");
...}


Но я не могу найти все ссылки на сервисный слой. У меня получиться только если я откажусь от contextConfigLocation в web.xml и перенесу все в bank-servlet.xml. Но мне кажется, что это не совсем по правилам. Почему мой services.xml не включается в applicationContext.getParent().

Я не уверен, что метод переноса будет правильным методом для доступа к среднему слою из контроллера, может есть какой-нибудь стандартный подход?

Буду благодарен за любую предоставленную информацию. Спасибо.
admin
Site Admin
 
Posts: 40
Joined: Wed Jun 22, 2011 6:54 am

Advertisement

Re: ContextLoaderListener и DispatcherServlet

Postby admin » Wed Jun 22, 2011 9:35 am

Я наконец понял, что было не так. Похоже я выбрал плохой пример для настройки своего contextConfigLocation в web.xml, где второй файл конфигурации всегда переписывал первый.

Должно было быть:

Code: Select all
<context-param>
        <param-name>contextConfigLocation</param-name>      
    <param-value>/WEB-INF/conf/services.xml /WEB-INF/conf/hibernate-dao.xml</param-value>             
    </context-param>


Было
Code: Select all
<context-param>
        <param-name>contextConfigLocation</param-name>      
   <param-value>/WEB-INF/conf/services.xml</param-value> 
   <param-value>/WEB-INF/conf/hibernate-dao.xml</param-value>       
  </context-param>


Тем не менее, часть моего вопроса остается открытой: доступ к слою сервиса через родительский контекст из контроллера считается приемлемым?

То есть:
Code: Select all
protected ModelAndView handleRequestInternal(HttpServletRequest request,
         HttpServletResponse response) throws Exception {
      
      AccountService accountService = (AccountService) 
                  getApplicationContext().getParent().getBean("accountService");
      Account account = accountService.createAccount();


..,где Account это domain pojo.
admin
Site Admin
 
Posts: 40
Joined: Wed Jun 22, 2011 6:54 am

Re: ContextLoaderListener и DispatcherServlet

Postby admin » Wed Jun 22, 2011 9:35 am

Нет. Просто сделайте инъекцию в ваш контроллер.

DispatcherServlet (или ApplicationContext загруженный здесь) имеют доступ ко всем бинам загруженных с помощью ContextLoaderListener. Поэтому просто делайте инъекцию вместо ненужного поиска...

Code: Select all
public class AccountController {

  private AccountService accountService;

  public void setAccountService(AccountService accountService) {
    this.accountService=accountService;
  }
}


xml:
Code: Select all
<bean class="AccountController" >
  <property name="accountService" ref="accountService" />
</bean>


ContextLoaderListener -> Services, daos и infrastructure
DispatcherServlet -> web материал (не xml, который содержит, сказанное выше)

Dispatcherservlet-ы applicationcontext автоматически имеют ContextLoaderListeners applicationcontext в качестве родителя.
admin
Site Admin
 
Posts: 40
Joined: Wed Jun 22, 2011 6:54 am



  • Advertisement

Return to Контейнер

Who is online

Users browsing this forum: No registered users and 2 guests