一、背景

  我们在Spring+SpringMVC+Mybatis的集成开发中,经常会遇到事务配置不起作用等问题,那么本文就来分析下出现这种问题可能的原因以及解决方式。

二、分析及原理窥探

  1.项目结构

  

  2.我们在spring-mvc.xml文件中进行如下配置,这种方式会成功扫描到带有@Controller注解的Bean,不会扫描带有@Service/@Repository注解的Bean,是正确的。

<context:component-scan base-package="com.hafiz.www.controller">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

  3.但是如下方式,不仅仅扫描到带有@Controller注解的Bean,还扫描到带有@Service/@Repository注解的Bean,可能造成事务不起作用等问题。

<context:component-scan base-package="com.hafiz.www">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

这是因为什么呢?下面让我们来从源码进行分析。

  1.<context:component-scan>会交给org.springframework.context.config.ContextNamespaceHandler处理.

registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser()); 

  2.ComponentScanBeanDefinitionParser会读取配置文件信息并组装成org.springframework.context.annotation.ClassPathBeanDefinitionScanner进行处理。

  3.如果没有配置<context:component-scan>的use-default-filters属性,则默认为true,在创建ClassPathBeanDefinitionScanner时会根据use-default-filters是否为true来调用如下代码:

protected void registerDefaultFilters() {
  this.includeFilters.add(new AnnotationTypeFilter(Component.class));
  ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
  try {
    this.includeFilters.add(new AnnotationTypeFilter(
      ((Class<? extends Annotation>) cl.loadClass("javax.annotation.ManagedBean")), false));
    logger.info("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
  }
  catch (ClassNotFoundException ex) {
    // JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
  }
  try {
    this.includeFilters.add(new AnnotationTypeFilter(
      ((Class<? extends Annotation>) cl.loadClass("javax.inject.Named")), false));
    logger.info("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
  }
  catch (ClassNotFoundException ex) {
    // JSR-330 API not available - simply skip.
  }
}

从以上源码我们可以看出默认ClassPathBeanDefinitionScanner会自动注册对@Component、@ManagedBean、@Named注解的Bean进行扫描。

  4.在进行扫描时会通过include-filter/exclude-filter来判断你的Bean类是否是合法的:

protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
for (TypeFilter tf : this.excludeFilters) {
if (tf.match(metadataReader, this.metadataReaderFactory)) {
return false;
}
}
for (TypeFilter tf : this.includeFilters) {
if (tf.match(metadataReader, this.metadataReaderFactory)) {
AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
if (!metadata.isAnnotated(Profile.class.getName())) {
return true;
}
AnnotationAttributes profile = MetadataUtils.attributesFor(metadata, Profile.class);
return this.environment.acceptsProfiles(profile.getStringArray("value"));
}
}
return false;
}

从以上源码可看出:扫描时首先通过exclude-filter 进行黑名单过滤,然后通过include-filter 进行白名单过滤,否则默认排除。

三、结论

  在spring-mvc.xml中进行如下配置:

<context:component-scan base-package="com.hafiz.www">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

则SpringMVC容器不仅仅扫描并注册带有@Controller注解的Bean,而且还扫描并注册了带有@Component的子注解@Service、@Reposity的Bean。因为use-default-filters默认为true。所以如果不需要默认的,则use-default-filters=“false”禁用掉。

  当我们进行上面的配置时,SpringMVC容器会把service、dao层的bean重新加载,从而造成新加载的bean覆盖了老的bean,但事务的AOP代理没有配置在spring-mvc.xml配置文件中,造成事务失效。解决办法是:在spring-mvc.xml配置文件中的context:component-scan标签中使用use-default-filters=“false”禁用掉默认的行为。

context:component-scan标签的use-default-filters属性的作用以及原理分析的更多相关文章

  1. component-scan标签的use-default-filters属性的作用以及原理分析

    一.背景 ​ 我们在Spring+SpringMVC+Mybatis的集成开发中,经常会遇到事务配置不起作用等问题,有时候就是因为包扫描出了问题,其中component-scan的标签的use-def ...

  2. HTML5 script 标签的 crossorigin 和integrity属性的作用

    Bootstrap 4 依赖的基础库中出现了两个新的属性 <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.slim.m ...

  3. [Spring Boot] Use Component Scan to scan for Bean

    Component Scan is important concept when we want to create Bean. Currently we know what, for the cla ...

  4. 在Asp.Net MVC中实现RequiredIf标签对Model中的属性进行验证

    在Asp.Net MVC中可以用继承ValidationAttribute的方式,自定制实现RequiredIf标签对Model中的属性进行验证 具体场景为:某一属性是否允许为null的验证,要根据另 ...

  5. CompareValues标签对Model中的属性进行验证

    在Asp.Net MVC中实现CompareValues标签对Model中的属性进行验证   在Asp.Net MVC中可以用继承ValidationAttribute的方式,自定制实现Model两个 ...

  6. HTML5中常用的标签(及标签的属性和作用)

    1.标签:<!DOCTYPE>作用:声明是文档中的第一成分,位于<html>标签之前. 2.标签:<html>作用:此元素可告知浏览器其自身是一个HTML文档.属性 ...

  7. HTML <img> 标签的 height 和 width 属性

    定义和用法 <img> 标签的 height 和 width 属性设置图像的尺寸. 提示:为图像指定 height 和 width 属性是一个好习惯.如果设置了这些属性,就可以在页面加载时 ...

  8. html的标签中 unselectable=on 属性的作用

    在IE浏览器中,当input获得焦点时,点击有unselectable="on"属性的标签时,不会触发onblur事件. 加上该属性的元素不能被选中. < !DOCTYPE ...

  9. HTML的iframe标签妙用 - 在线执行前端代码的网站原理是什么?

    在我自己的日常前端开发中,其实iframe标签出现的次数并不是很多.作为一个很古老(浏览器兼容性非常好)的标签,有必要去了解一下它的典型应用场景. (图片说明:所有浏览器都支持iframe,无论什么版 ...

随机推荐

  1. Bzoj1076 [SCOI2008]奖励关

    Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1935  Solved: 1053 Description 你正在玩你最喜欢的电子游戏,并且刚刚进入一 ...

  2. 关于 m4 文本处理引擎

    使用 m4 开源项目还是挺多的,之前看到都有的怕怕的,选择自动略过.今天鼓起勇气来学习一波. 首先 m4 processor 是一个“宏定义”处理器,也就是说,他是一个纯粹的文本处理器,干些管理模板, ...

  3. 《图解HTTP》阅读笔记

    HTTP基础的简单理解 在了解HTTP协议之前,我们先了解下TCP/IP的参考模型,TCP/IP参考模型分为四层:应用层.传输层.网络层.链路层(数据链路层). 应用层:为不同的网络应用提供所需的服务 ...

  4. 如何在mac本上安装android sdk 避免被墙

    众所周知的原因,google的很多网站在国内无法访问,苦逼了一堆天朝程序员,下是在mac本上折腾android 开发环境的过程: 一.先下载android sdk for mac 给二个靠谱的网址: ...

  5. websocket

    websocket是一个协议,在单个TCP连接上提供全双工通信.  websocket被设计并被实现在 web浏览器和 web 服务器上,但是它可以被用于任何c/s 架构的应用程序中. websock ...

  6. UI

    http://semantic-ui.com/introduction/getting-started.html

  7. session

    小结

  8. python模块(json和pickle模块)

    json和pickle模块,两个都是用于序列化的模块 • json模块,用于字符串与python数据类型之间的转换 • pickle模块,用于python特有类型与python数据类型之间的转换 两个 ...

  9. [Data Structure] LCSs——最长公共子序列和最长公共子串

    1. 什么是 LCSs? 什么是 LCSs? 好多博友看到这几个字母可能比较困惑,因为这是我自己对两个常见问题的统称,它们分别为最长公共子序列问题(Longest-Common-Subsequence ...

  10. Android基础 : Android ContentProvider

    Android 应用程序通过ContentProvider实现方式统一的数据共享功能. 外界的程序通过ContentResolver接口可以访问ContentProvider提供的数据,在Activi ...