spring组件扫描<context:component-scan/>使用详解

本文详细解析Spring框架中组件扫描的功能及其配置策略,包括如何使用<context:component-scan>标签,如何通过过滤器引入和排除目标类,以及在实际应用中遇到的问题与解决方法。特别强调了不同类型过滤器的使用场景与限制,如正则表达式过滤器的正确应用,并提供了实例代码以供参考。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关于spring自动检测组件的使用方式网上太多了,而且也不是我记录的重点,我想说下一点可能你还不知道的经验
我们知道如果不想在xml文件中配置bean,我们可以给我们的类加上spring组件注解,只需再配置下spring的扫描器就可以实现bean的自动载入。
 
下面是引用spring framework开发手册中的一段话

Spring 2.5引入了更多典型化注解(stereotype annotations): @Component@Service @Controller@Component是所有受Spring管理组件的通用形式; 而@Repository@Service @Controller则是@Component的细化, 用来表示更具体的用例(例如,分别对应了持久化层、服务层和表现层)。也就是说, 你能用@Component来注解你的组件类, 但如果用@Repository@Service @Controller来注解它们,你的类也许能更好地被工具处理,或与切面进行关联。 例如,这些典型化注解可以成为理想的切入点目标。当然,在Spring Framework以后的版本中, @Repository@Service @Controller也许还能携带更多语义。如此一来,如果你正在考虑服务层中是该用 @Component还是@Service, 那@Service显然是更好的选择。同样的,就像前面说的那样, @Repository已经能在持久化层中进行异常转换时被作为标记使用了。”

 

下面是网上目前关于组件扫描最详细的介绍

Spring applicationContext.xml的<context:component-scan>標籤用途比我想像的還要實用。而且後來才知道,有了<context:component-scan>,另一個<context:annotation-config/>標籤根本可以移除掉,因為被包含進去了。原本我survery Spring3通常只配置成<context:component-scan base-package="com.foo.bar"/>,意即在base-package下尋找有@Component和@Configuration的target Class。而現在如下的飯粒:

<context:component-scan base-package="com.foo" use-default-filters="false">
<context:include-filter type="regex" expression="com.foo.bar.*Config"/>
<context:include-filter type="regex" expression="com.foo.config.*"/>
</context:component-scan>

  <context:component-scan>提供兩個子標籤:<context:include-filter>和<context:exclude-filter>各代表引入和排除的過濾。而上例把use-default-filters屬性設為false,意即在base-package所有被宣告為@Component和@Configuration等target Class不予註冊為bean,由filter子標籤代勞。

  filter標籤在Spring3有五個type,如下:

Filter TypeExamples ExpressionDescription
annotationorg.example.SomeAnnotation符合SomeAnnoation的target class
assignableorg.example.SomeClass指定class或interface的全名
aspectjorg.example..*Service+AspectJ語法
regexorg\.example\.Default.*Regelar Expression
customorg.example.MyTypeFilterSpring3新增自訂Type,實作org.springframework.core.type.TypeFilter

  所以上例用的regex就有個語病,com.foo.config.* 可以找到com.foo.config.WebLogger,但也可以找到com1fool2config3abcde,因為小數點在Regex是任意字元,是故要用\.把小數點跳脫為佳。(2010/3/15補充:但要使用\.方式,其use-default-filters不能為false,否則抓不到,感覺是Bug)

  Spring3提供豐富的Filter支援,有益配置策略,不需面臨Configuration Hell,比如Regex的com\.foo\.*\.action\.*Config,這樣就可以找到com.foo package下所有action子package的*Config的target class。

 

我按他的例子,配置了我自己的如下:

<context:component-scan base-package="com.xhlx.finance.budget"   >
  <context:include-filter type="regex" expression="com.lee.finance.budget.service.*"/>
  <context:include-filter type="regex" expression="com.lee.finance.budget.security.*"/> 
</context:component-scan>
但是死活扫描不到,网上又没有更好的讲解,没办法只好自己试,改成
<context:component-scan base-package="com.xhlx.finance.budget" >
   <context:include-filter type="regex" expression="com.lee.finance.budget.*"/>
</context:component-scan>
这样连没有加注解的类也扫描并实例化,结果报错,因为有的类根本就没有默认的构造函数不能实例化,能不报错吗
改成
<context:component-scan base-package="com.xhlx.finance.budget"   >
  <context:include-filter type="regex" expression="com\.lee\.finance\.budget\.service.*"/>  
</context:component-scan>问题依旧
<context:component-scan base-package="com.xhlx.finance.budget" >
   <context:include-filter type="regex" expression="com.lee.finance.budget.service.TestService"/>
</context:component-scan>
嘿,这次可以了,写全限定名就可以,表达式却不行,但是如果我有成千上百个还得一个一个这样配置啊?不行,继续研究,我想有个base-package的配置,从表面意思来看这是个“基本包”,是否表示下面的过滤路径是基于这个包的呢?于是试着改成
<context:component-scan base-package="com.xhlx.finance.budget" >
   <context:include-filter type="regex" expression=".service.*"/>
</context:component-scan>
嘿,行了。看来,别人写的东西虽然能给你很多帮助,但也不一定全对啊,我希望每个人都坚持分享实践出来的东西,而不是人云亦云。
 
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!--开启Spring的注解--> <context:annotation-config/> <!--Spring的注解扫描包路径--> <context:component-scan base-package="com.example"/> <!--加载数据源连接池--> <bean name="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://127.0.0.1/apsfc?serverTimezone=UTC"/> <property name="username" value="root"/> <property name="password" value="root"/> </bean> <!--创建SqlSessionFactory对象--> <bean name="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!--注入数据源连接池--> <property name="dataSource" ref="druidDataSource"/> <!--注入Mybatis的主配置文件--> <property name="configLocation" value="classpath:sqlMapConfig.xml"/> <!--配置DAO的映射文件扫描路径--> <property name="mapperLocations" value="classpath:mapper/*.xml"/> </bean> <!--加载DAO接口扫描--> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <!--将SqlSessionFactory对象进行注入--> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> <!--配置DAO接口的扫描基础路径--> <property name="basePackage" value="com.example.meal_ordering_system.dao.**"/> </bean> <!--加载事务管理器--> <bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!--加载数据源连接池--> <property name="dataSource" ref="druidDataSource"/> </bean> <!--配置事务增强通知--> <!--transaction-manager加载指定的事务管理器--> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <!--事务规则列表--> <tx:attributes> <!--propagation定义动作的规则--> <!--REQUIRED阻断操作--> <!--NOT_SUPPORTED非阻断操作--> <!--对新增数据操作的规则定义--> <tx:method name="insert*" propagation="REQUIRED"/> <tx:method name="add*" propagation="REQUIRED"/> <!--对修改数据操作的规则定义--> <tx:method name="update*" propagation="REQUIRED"/> <tx:method name="edit*" propagation="REQUIRED"/> <!--对删除数据操作的规则定义--> <tx:method name="delete*" propagation="REQUIRED"/> <!--对查询数据操作的规则定义--> <tx:method name="get*" propagation="NOT_SUPPORTED"/> <tx:method name="select*" propagation="NOT_SUPPORTED"/> <tx:method name="query*" propagation="NOT_SUPPORTED"/> </tx:attributes> </tx:advice> <!--托管通知工具类--> <bean name="advice" class="com.example.meal_ordering_system.util.AdviceUtil"/> <!--切面的配置--> <aop:config> <!--切面定义在Service层--> <aop:pointcut id="pointCut" expression="execution(* com.example.meal_ordering_system.service..*(..))"/> <!--将事务增强通知与切面进行绑定--> <aop:advisor advice-ref="txAdvice" pointcut-ref="pointCut"/> <!--切面织入--> <aop:aspect ref="advice"> <aop:before method="before" pointcut-ref="pointCut"/> <aop:after method="after" pointcut-ref="pointCut"/> <aop:around method="around" pointcut-ref="pointCut"/> <aop:after-throwing method="exception" pointcut-ref="pointCut"/> </aop:aspect> </aop:config> </beans>
最新发布
05-23
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值