<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
在配置文件中,默认情况下,
会自动使用名称为transactionManager的事务管理器。
所以,如果定义的事务管理器名称为transactionManager,那么就可以直接使用
@Transactional可以加在Controller层,但是前提是
位置必须放置正确:
在spring-framework-reference.pdf文档中有这样一段话:
only looks for @Transactional on beans in the same application context it is defined in. This means that, if you put
in a WebApplicationContext for a DispatcherServlet, it only checks for @Transactional beans in your controllers, and not your services.
这句话的意思是,
只会查找和它在相同的应用上下文件中定义的bean上面的@Transactional注解,如果你把它放在Dispatcher的应用上下文中(意思就是说如果你用的是servlet的方式加载spring-mvc.xml文件,并且将
写在spring-mvc.xml文件中),它只检查控制器上的@Transactional注解,而不是你services上的@Transactional注解。
<context-param>
<param-name>contextConfigLocationparam-name>
<param-value>
classpath:applicationContext.xml
param-value>
context-param>
<servlet-name>springmvcservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:springmvc.xmlparam-value>
init-param>
servlet>
另外一种方式是可以将spring的所有配置文件都放在context-param(上下文参数)中进行加载。
<context-param>
<param-name>contextConfigLocationparam-name>
<param-value>
classpath:applicationContext.xml,
classpath:spring-servlet.xml
param-value>
context-param>
Spring父子容器:
为什么上面另外一种方式可以将spring的所有配置文件都放在context-param(上下文参数)中,引出了一个父子容器的概念,而典型的父子容器就是spring和springmvc同时使用的时候。分别ContextLoaderListener 创建的 容器是父容器,DispatcherServlet 创建的容器是子容器。
而父容器和子容器的区别。比如父容器有a.b.c三个bean对象,子容器有d.e.f三个bean对象,子容器就可以通过getBean方法调用父容器的a.b.c bean对象,而父容器不能通过getBean拿到子容器的d.e.f三个bean对象。但是这里有一个例外property-placeholder,容器中读取的配置文件就是私有的,互相不能访问。其中也要弄清楚的是父子容器并不是一种包含关系,而是平行关系,但是在子容器中有一个parent,指向父容器,也就是说子容器在通过getBean访问父容器中的bean对象时是通过parent访问。
这种做法的实际意思就是在一个JVM,只有一个树状结构的容器树。可以通过子容器访问父容器资源。就比如在实际开发中使用ssm框架,spring可以管理service,mapper,springmvc管理controller,mybatis编写mapper,controller就需要调用service,service调用mapper,因为springmvc容器是spring的子容器,可以通过父容器找到service和mapper,但是在service中却是找不到controller的。保证一种资源的局部性。
这也就是为什么如果将事务
配置在子容器,即Dispatcher的应用上下文中,会导致父容器的service事务不起作用,因为父容器是访问不了子容器资源的,而如果将配置在父容器,不仅servicer能进行加事务注解,controller也可以,因为子容器能访问到父容器资源。
spring-servlet.xml如果配置在
,即被配置在servlet的初始化过程中,所以如果不初始化servlet,那么spring-servlet.xml是不会被发现的。如果我们将定时器的注解加载过程放在spring-servlet.xml中,如果不进行页面的刷新,是不会经过DispatcherServlet这个跳转器的,所以也就不会加载spring-servlet.xml文件,所以定时任务可能就不会被触发。如果经过了这个DispatcherServlet这个跳转器,即被初始化。所以定时任务才会被执行。这是servlet的基本知识,浏览器需要访问时,servlet才会进行真正的实例化。
更多请详看:
https://blog.csdn.net/weixin_46228112/article/details/124602459
https://blog.csdn.net/qq_39326498/article/details/126663514
配置注解映射器和适配器在spring3.1之前使用org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping注解映射器。
在spring3.1之后使用org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping注解映射器。
在spring3.1之前使用org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter注解适配器。
在spring3.1之后使用org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter注解适配器。
使用 mvc:annotation-driven代替上边注解映射器和注解适配器配置
mvc:annotation-driven默认加载很多的参数绑定方法,比如json转换解析器就默认加载了,如果使用mvc:annotation-driven不用配置上边的RequestMappingHandlerMapping和RequestMappingHandlerAdapter
实际开发时使用