Transaction在Controller层的摸索
一般开拓中事务要求我们放在Service层,但是有些环境,我们大概会要求放在Controller层,你有没有遇到过这样的需求呢?那么放到Controller层事务会生效吗?会发生什么问题呢?下面一起来看看
I、透过现象看本质
第一种环境
@RestController @RequestMapping("/city") public class CityControllerImpl implements CityController { @Autowired private CityService cityService; @Override @RequestMapping(value = "getCity",method = RequestMethod.GET,produces = MediaType.APPLICATION_JSON_UTF8_VALUE) @Transcational public BaseResult<City> getCity(@RequestParam("id") Integer id) { City one = cityService.getOne(id); BaseResult<City> baseResult=new BaseResult<>(); baseResult.setData(one); return baseResult; } }
第二种环境
@RestController @RequestMapping("/city") public class CityControllerImpl { @Autowired private CityService cityService; @RequestMapping(value = "getCity",method = RequestMethod.GET,produces = MediaType.APPLICATION_JSON_UTF8_VALUE) @Transactional public BaseResult<City> getCity(@RequestParam("id") Integer id) { City one = cityService.getOne(id); BaseResult<City> baseResult=new BaseResult<>(); baseResult.setData(one); return baseResult; } }
{ data: null, message: null, status: 0 }
第三种环境
II、熟悉本质解现象
1. 区别
可以看出,我们两个Controller的区别就是一个有实现接口,一个没有实现,为什么不同会这么大呢?
2. 事务的本质
我们知道事务是基于署理实现的,今朝Spring中有JDK动态署理和CGLIB署理两种署理,那么跟Spring选择的署理有没有干系呢?我们看一下Spring在署理类的时候选择利用何种署理的源代码。如下:
@Override public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { Class<?> targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException("TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation."); } if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } return new ObjenesisCglibAopProxy(config); } else { return new JdkDynamicAopProxy(config); } }
这是Spring建设署理较量焦点的一段代码,在类 DefaultAopProxyFactory
中,不管加没有加接口,Spring看到了@Transactional
注解城市给我们的Controller注册为一个署理工具。留意:Spring并非对所有的Controller城市建设署理类,昆山软件开发,如果我们的Controller没有袒露任何切面,Spring并不会建设一个署理类
,这里大概各人会感想奇怪,我们这里打个TAG,文末讲授。
继承方才的话题,劳务派遣管理系统,第一种环境,由于我们的Controller有接口,所以就走了JDK署理,相反第二种走了Cglib署理。OK, 我们的CityControllerImpl此刻是一个署理类。那么为什么会产生404异常呢?
springmvc的道理">3. SpringMvc的道理
为什么Controller酿成署理之后,就会404异常了,必定跟我们的SpringMVC有关,我们看一下SpringMVC的焦点类 AbstractHandlerMethodMapping
这个类可以绑定URL和需要执行处理惩罚器的哪个要领。这个抽象类实现了initializingBean
接口,其实主要的注册URL操纵则是通过这个接口的afterPropertiesSet()接口要领来挪用的。然后挪用initHandlerMethods
要领举办绑定URL。要领具体如下:
protected void initHandlerMethods() { if (logger.isDebugEnabled()) { logger.debug("Looking for request mappings in application context: " + getApplicationContext()); } String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) : getApplicationContext().getBeanNamesForType(Object.class)); for (String beanName : beanNames) { if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) { Class<?> beanType = null; try { beanType = getApplicationContext().getType(beanName); } catch (Throwable ex) { // An unresolvable bean type, probably from a lazy bean - let's ignore it. if (logger.isDebugEnabled()) { logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex); } } if (beanType != null && isHandler(beanType)) { detectHandlerMethods(beanName); } } } handlerMethodsInitialized(getHandlerMethods()); }