Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
479 views
in Technique[技术] by (71.8m points)

java - Spring-MVC : Creating a good infrastructure(configuration) and avoiding duplicates

I am working on a Spring-MVC application since some time. Recently I ran into some problems with @Scheduled methods, and I noticed that the whole configuration is getting loaded 4 times. Because of that the @Scheduled methods are getting called 4 times.

The 3 configurations which are not correct, die out with NullPointerException(is what I was told on SO), and the one survives. I am very much interested to know how can I configure my project properly, so there is only one configuration which is loaded, and not 4, and learn about Spring-MVC, Spring in the process.

As the servlet-context is large, I am posting web.xml on pastebin, so I can have place to put JAVA code as well.

Servlet-context.xml :

  <context:annotation-config/>

    <mvc:annotation-driven>
        <mvc:argument-resolvers>
            <beans:bean class="org.springframework.mobile.device.DeviceWebArgumentResolver"/>
        </mvc:argument-resolvers>
    </mvc:annotation-driven>
    <mvc:interceptors>
        <beans:bean class="org.springframework.mobile.device.DeviceResolverHandlerInterceptor"/>
    </mvc:interceptors>

    <mvc:default-servlet-handler/>

    <resources mapping="/resources/" location="/resources/"/>

    <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>

    <beans:bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
                destroy-method="close">
        <beans:property name="driverClassName" value="org.postgresql.Driver"/>
        <beans:property name="url"
                        value="jdbc:postgresql://localhost:5432/dbname"/>
        <beans:property name="username" value="dbuser"/>
        <beans:property name="password" value="dbpass"/>
        <beans:property name="removeAbandoned" value="true"/>
        <beans:property name="removeAbandonedTimeout" value="20"/>
        <beans:property name="defaultAutoCommit" value="false"/>
    </beans:bean>


    <!-- Hibernate 4 SessionFactory Bean definition -->
    <beans:bean id="hibernate4AnnotatedSessionFactory"
                class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <beans:property name="dataSource" ref="dataSource"/>
        <beans:property name="annotatedClasses">
            <beans:list>
                <beans:value>com.journaldev.spring.model.Person</beans:value>
                <beans:value>com.journaldev.spring.model.Notes</beans:value>
                <beans:value>com.journaldev.spring.model.Canvas</beans:value>
                <beans:value>com.journaldev.spring.model.Section</beans:value>
                <beans:value>com.journaldev.spring.model.Attachment</beans:value>

                <beans:value>com.journaldev.spring.model.GroupAccount</beans:value>
                <beans:value>com.journaldev.spring.model.GroupMembers</beans:value>
                <beans:value>com.journaldev.spring.model.GroupCanvas</beans:value>
                <beans:value>com.journaldev.spring.model.GroupSection</beans:value>
                <beans:value>com.journaldev.spring.model.GroupNotes</beans:value>
                <beans:value>com.journaldev.spring.model.GroupAttachments
                </beans:value>

                <beans:value>com.journaldev.spring.model.Token</beans:value>
                <beans:value>com.journaldev.spring.model.WaitingMembers
                </beans:value>
                <beans:value>com.journaldev.spring.model.NoteHistory</beans:value>
                <beans:value>com.journaldev.spring.model.GroupNoteHistory
                </beans:value>

                <beans:value>com.journaldev.spring.model.Feedback</beans:value>
                <beans:value>com.journaldev.spring.model.UnreadNotes</beans:value>
                <beans:value>com.journaldev.spring.model.SessionState</beans:value>
                <beans:value>com.journaldev.spring.model.FeatureRequest
                </beans:value>
                <beans:value>com.journaldev.spring.model.FeatureComment
                </beans:value>
                <beans:value>com.journaldev.spring.model.FeatureLike</beans:value>
                <beans:value>com.journaldev.spring.model.OnlineUsers</beans:value>
                <beans:value>com.journaldev.spring.model.NoteCount</beans:value>
                <beans:value>com.journaldev.spring.model.NoteLock</beans:value>
                <beans:value>com.journaldev.spring.model.ChatMessages</beans:value>
                <beans:value>com.journaldev.spring.model.Conversation</beans:value>
                <beans:value>com.journaldev.spring.model.Replies</beans:value>
                <beans:value>com.journaldev.spring.model.Notification</beans:value>
                <beans:value>com.journaldev.spring.model.Statistics</beans:value>
                <beans:value>com.journaldev.spring.model.PrivateChannel</beans:value>
                <beans:value>com.journaldev.spring.model.GroupChannels</beans:value>
            </beans:list>
        </beans:property>
        <beans:property name="hibernateProperties">
            <beans:props>
                <beans:prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQL9Dialect
                </beans:prop>
                <beans:prop key="hibernate.show_sql">false</beans:prop>
                <beans:prop key="connection.pool_size">200</beans:prop>
                <beans:prop key="c3p0.max_size">200</beans:prop>
                <beans:prop key="c3p0.timeout">1000</beans:prop>
             <!--   <beans:prop key="hibernate.jdbc.batch_size">1000</beans:prop>
                <beans:prop key="hibernate.order_updates">true</beans:prop>-->
                <beans:prop key="hibernate.hbm2ddl.auto">update</beans:prop>
            </beans:props>
        </beans:property>
    </beans:bean>

    <task:annotation-driven/>

    <tx:annotation-driven transaction-manager="transactionManager"/>

    <beans:bean id="transactionManager"
                class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <beans:property name="sessionFactory" ref="hibernate4AnnotatedSessionFactory"/>
    </beans:bean>

    <!-- Person beans being here -->
    <beans:bean id="personDAO" class="com.journaldev.spring.dao.PersonDAOImpl">
        <beans:property name="sessionFactory"
                        ref="hibernate4AnnotatedSessionFactory"/>
    </beans:bean>
    <beans:bean id="personService"
                class="com.journaldev.spring.service.PersonServiceImpl">
        <beans:property name="personDAO" ref="personDAO"/>
    </beans:bean>


    <!--  <beans:bean id="bayeux" class="org.cometd.server.BayeuxServerImpl" init-method="start" destroy-method="stop">
          <beans:property name="transports">
              <beans:list>
                  <beans:bean id="jsonTransport" class="org.cometd.server.transport.JSONTransport">
                      <beans:constructor-arg ref="bayeux"/>
                  </beans:bean>
                  <beans:bean id="jsonpTransport" class="org.cometd.server.transport.JSONPTransport">
                      <beans:constructor-arg ref="bayeux"/>
                  </beans:bean>
              </beans:list>
        </beans:property>
      </beans:bean>-->

    <!-- Group Account beans begin here -->

    <beans:bean id="groupAccountDAO"
                class="com.journaldev.spring.dao.GroupAccountDAOImpl">
        <beans:property name="sessionFactory"
                        ref="hibernate4AnnotatedSessionFactory"/>
    </beans:bean>

    <beans:bean id="groupAccountService"
                class="com.journaldev.spring.service.GroupAccountServiceImpl">
        <beans:property name="groupAccountDAO" ref="groupAccountDAO"/>
    </beans:bean>

    <!--Group Members bean begin here -->
    <beans:bean id="groupMembersDAO"
                class="com.journaldev.spring.dao.GroupMembersDAOImpl">
        <beans:property name="sessionFactory"
                        ref="hibernate4AnnotatedSessionFactory"/>
    </beans:bean>

    <beans:bean id="groupMembersService"
                class="com.journaldev.spring.service.GroupMembersServiceImpl">
        <beans:property name="groupMembersDAO" ref="groupMembersDAO"/>
    </beans:bean>

    <!-- Notes bean begin here -->
    <beans:bean id="notesDAO" class="com.journaldev.spring.dao.NotesDAOImpl">
        <beans:property name="sessionFactory"
                        ref="hibernate4AnnotatedSessionFactory"/>
    </beans:bean>

    <beans:bean id="notesService"
                class="com.journaldev.spring.service.NotesServiceImpl">
        <beans:property name="notesDAO" ref="notesDAO"/>
    </beans:bean>

    <!--GroupNotes begin here -->

    <beans:bean id="groupNotesDAO" class="com.journaldev.spring.dao.GroupNotesDAOImpl">
        <beans:property name="sessionFactory"
                        ref="hibernate4AnnotatedSessionFactory"/>
    </beans:bean>

    <beans:bean id="groupNotesService"
                class="com.journaldev.spring.service.GroupNotesServiceImpl">
        <beans:property name="groupNotesDAO" ref="groupNotesDAO"/>
    </beans:bean>


    <!-- Canvas Beans begin here -->

    <beans:bean id="canvasDAO" class="com.journaldev.spring.dao.CanvasDAOImpl">
        <beans:property name="sessionFactory"
                        ref="hibernate4AnnotatedSessionFactory"/>
    </beans:bean>

    <beans:bean id="canvasService"
                class="com.journaldev.spring.service.CanvasServiceImpl">
        <beans:property name="canvasDAO" ref="canvasDAO"/>
    </beans:bean>

    <!--Group Canvas beans begin here -->
    <beans:bean id="groupCanvasDAO"
                class="com.journaldev.spring.dao.GroupCanvasDAOImpl">
        <beans:property name="sessionFactory"
                        ref="hibernate4AnnotatedSessionFactory"/>
    </beans:bean>

    <beans:bean id="groupCanvasService"
                class="com.journaldev.spring.service.GroupCanvasServiceImpl">
        <beans:property name="groupCanvasDAO" ref="groupCanvasDAO"/>
    </beans:bean>

    <!-- Section beans begin here -->
    <beans:bean id="sectionDAO" class="com.journaldev.spring.dao.SectionDAOImpl">
        <beans:property name="sessionFactory"
                        ref="hibernate4AnnotatedSessionFactory"/>
    </beans:bean>

    <beans:bean id="sectionService"
                class="com.journaldev.spring.service.SectionServiceImpl">
        <beans:property name="sectionDAO" ref="sectionDAO"/>
    </beans:bean>

    <!-- Group Section beans 

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The point of using annotations is to remove the need for xml configuration. If you are using the Spring @Service and @Repository annotations then you can remove all the service and dao definitions from the xml posted above and replace them with with one line.

<context:component-scan base-package="x.y.z.service, x.y.z.repository" />

You can then update all your service classes to be like below using the @Autowired annotation to have Spring inject the relevant DAO:

@Service
@Transactional
public class CanvasServiceImpl implements CanvasService {

    @Autowired
    private CanvasDAO canvasDAO;
}

You also load the Spring security context multiple times in your web.xml. Once via The ContextLoaderListener and once via the RequestDispatcher configuration:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
        http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    version="3.0">

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring/root-context.xml,/WEB-INF/spring/appServlet/security-applicationContext.xml</param-value>
    </context-param>

    <session-config>
        <session-timeout>1440</session-timeout>
    </session-config>
    <listener>
        <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
    </listener>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    ...

    <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/security-applicationContext.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
        <async-supported>true</async-supported>
    </servlet>

</web-app> 

And then, just to finish things off you also import the web application configuration in the security context each time it is loaded.

<import resource="servlet-context.xml" /> 

I would normally configure as outlined here. I believe this is considered best practice. Essentially you have the Dispatcher Servlet initialize only the web related stuff. You have the Listener initialize the non-web stuff.

http://simone-folino.blogspot.co.uk/2012/05/dispatcherservlet-vs.html


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

57.0k users

...