Spring-MVC:创建良好的基础架构(配置)并避免重复

我有一段时间以来一直致力于Spring-MVC应用程序。 最近我遇到了@Scheduled方法的一些问题,我注意到整个配置加载了4次。 因为@Scheduled方法被调用了4次。

3个配置不正确,用NullPointerException消失(这是我在SO上被告知的),并且幸存下来了。 我非常有兴趣知道如何正确配置我的项目,因此只有一个配置被加载,而不是4,并且在此过程中了解Spring-MVC,Spring。

由于servlet-context很大,我在pastebin上发布web.xml,所以我也可以放置JAVA代码。

Servlet-context.xml:

                             com.journaldev.spring.model.Person com.journaldev.spring.model.Notes com.journaldev.spring.model.Canvas com.journaldev.spring.model.Section com.journaldev.spring.model.Attachment com.journaldev.spring.model.GroupAccount com.journaldev.spring.model.GroupMembers com.journaldev.spring.model.GroupCanvas com.journaldev.spring.model.GroupSection com.journaldev.spring.model.GroupNotes com.journaldev.spring.model.GroupAttachments  com.journaldev.spring.model.Token com.journaldev.spring.model.WaitingMembers  com.journaldev.spring.model.NoteHistory com.journaldev.spring.model.GroupNoteHistory  com.journaldev.spring.model.Feedback com.journaldev.spring.model.UnreadNotes com.journaldev.spring.model.SessionState com.journaldev.spring.model.FeatureRequest  com.journaldev.spring.model.FeatureComment  com.journaldev.spring.model.FeatureLike com.journaldev.spring.model.OnlineUsers com.journaldev.spring.model.NoteCount com.journaldev.spring.model.NoteLock com.journaldev.spring.model.ChatMessages com.journaldev.spring.model.Conversation com.journaldev.spring.model.Replies com.journaldev.spring.model.Notification com.journaldev.spring.model.Statistics com.journaldev.spring.model.PrivateChannel com.journaldev.spring.model.GroupChannels     org.hibernate.dialect.PostgreSQL9Dialect  false 200 200 1000 <!-- 1000 true--> update                <!--            -->                                                                                                                                                                                             <!---->                                  

如上所述, 这是web.xml的URL, 这里是security-application.context.xml

在整个项目中,模型如下所示:

 @Entity @Table(name = "canvas") public class Canvas { @Id @Column(name="canvasid") @GeneratedValue(strategy = GenerationType.SEQUENCE,generator = "canvas_gen") @SequenceGenerator(name = "canvas_gen",sequenceName = "canvas_seq") @Index(name = "canvasid") private int canvasid; //Other variables, mappings, getters, setters } 

DAO在整个项目中看起来像这样:

 @Transactional @Repository public class CanvasDAOImpl implements CanvasDAO{ private SessionFactory sessionFactory; public void setSessionFactory(SessionFactory sf){ this.sessionFactory = sf; } private Session session; public void setSession(Session session){this.session = session;} @overrride public returnType methodName(params..){ session = this.sessionFactory.getCurrentSession(); } } 

最后,我的服务层看起来像这样:

 @Service @Transactional public class CanvasServiceImpl implements CanvasService { private CanvasDAO canvasDAO; public void setCanvasDAO(CanvasDAO canvasDAO) { this.canvasDAO = canvasDAO; } //methods } 

我在整个java文件中保持了相同的结构。 为什么我的配置被加载了4次而不是1次。对于优化总体上有任何建议。 谢谢。

编辑

我的服务看起来像这样:

 @Service @Transactional public class AttachmentServiceImpl implements AttachmentService{ @Autowired private AttachmentDAO attachmentDAO; // The guy below stays or not? why? public void setAttachmentDAO(AttachmentDAO attachmentDAO){ this.attachmentDAO = attachmentDAO; } } 

您的代码和配置可以改进很多东西。 让我们从您的dao开始,不要将Session存储在实例变量中,我强烈建议使用构造函数注入来获取所需的依赖项。 考虑到这一点,你的dao应该看起来像这样。

 @Transactional @Repository public class CanvasDAOImpl implements CanvasDAO{ private final SessionFactory sessionFactory; @Autowired public CanvasDAOImpl(SessionFactory sessionFactory) { this.sessionFactory=sessionFactory; } @overrride public returnType methodName(params..){ Session session = this.sessionFactory.getCurrentSession(); // Do stuff with the session. } } 

没有更多的setter(尤其不是Session !)只是一个简单的类。 这同样适用于@Service类。

 @Service @Transactional public class CanvasServiceImpl implements CanvasService { private final CanvasDAO canvasDAO; public CanvasServiceImpl(CanvasDAO canvasDAO) { this.canvasDAO=canvasDAO; } //methods } 

在您的配置中,您已明确定义了所有@Repository@Service bean。 您还有一个 ,它已经检测到所有@Component 。 删除所有显式声明的@Repository@Service bean。 这将真正清理你的配置!

在你的hibernate配置中, c3p0connection属性是无用的,因为你正在注入一个DataSource而hibernate不是在管理它,而是Spring。 删除这些行。 此外,要进一步清理此配置,而不是指定处理添加packagesToScan所需的每个类,以便它自动检测@Entity注释的bean。

使用已经隐含了因此你可以删除它,因为它基本上复制了东西。

您已明确定义了一个RequestMappingHandlerMapping ,它没有做任何事情,因为已经有一个由 。 它只占用内存,在类路径上检测到Jackson2自动注册的MappingJackson2HttpMessageConverter,因此无需这样做。

由于忘记使用元素注册拦截器,因此查找Locale不适用于所有URL。

将所有建议应用于您的类和配置时,其余配置如下所示。

                                   org.hibernate.dialect.PostgreSQL9Dialect false  update                                   

但是你真的应该在ContextLoaderListener加载的东西中拆分基本上所有BUT @Controller以及DispatcherServlet加载的内容只是@Controller和web相关的bean。

所以servlet-context.xml看起来应该是这样的。

                                             

然后将删除的内容和 (或修改它)添加到root-context.xml

                     org.hibernate.dialect.PostgreSQL9Dialect false  update          

security-context.xml删除

最后让DispatcherServlet加载servlet-context.xml而不是security-context.xml

现在,由于您不再为每个上下文加载两次bean,因此应该减少内存占用,并且不应再有4个预定作业。 理想情况下,您的Email类也应该是Spring托管bean,我建议使用简化发送电子邮件的JavaMailSender API。

所以基本上你面前的任务是主要删除东西,你最终会得到更少的代码和更少的配置,并且仍然可以实现相同的目标。

如需更多动手实践,我可以出租;)……

使用注释的目的是消除对xml配置的需要。 如果您正在使用Spring @Service@Repository注释,那么您可以从上面发布的xml中删除所有服务和dao定义,并用一行替换它们。

  

然后,您可以使用@Autowired注释更新所有服务类,使Spring注入相关的DAO:

 @Service @Transactional public class CanvasServiceImpl implements CanvasService { @Autowired private CanvasDAO canvasDAO; } 

您还可以在web.xml中多次加载Spring安全性上下文。 一旦通过ContextLoaderListener并通过RequestDispatcher配置一次:

    contextConfigLocation /WEB-INF/spring/root-context.xml,/WEB-INF/spring/appServlet/security-applicationContext.xml   1440   org.springframework.web.context.request.RequestContextListener   org.springframework.web.context.ContextLoaderListener  ...  appServlet org.springframework.web.servlet.DispatcherServlet  contextConfigLocation /WEB-INF/spring/appServlet/security-applicationContext.xml  1 true   

然后,只需完成一些操作,您还可以在每次加载时在安全上下文中导入Web应用程序配置。

  

我通常会配置如此处所述。 我相信这被认为是最佳做法。 基本上你有Dispatcher Servlet只初始化与web相关的东西。 你有Listener初始化非web内容。

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