关于spring的context:component-scan

前言

在使用maven中,多模块依赖spring配置文件,出现一些问题,最后的办法使用context:conmponent-scan来解决,具体我将在正文中详细描述问题

正文

出现的问题

在使用maven中,我将项目简单的三层模型分成了多模块来做,比如,dao层,我设定一个模块,service层设定一个模块,controller层我设定为一个模块,在dao层中,我配置了spring的基本的数据源,注解扫描,事物,然后在service,我依赖与dao模块,这样我service模块的spring配置文件就不需要配置dao模块spring已经配置好的信息了。现在的问题是,service使用了dao模块的spring注解扫描,而我的注解扫描定义如下

<context:component-scan base-package="org.persistent">

这样出现的问题是,我service中的org.service包下的@service就无法扫描进去。
嗯,解决办法很简单,我把base-package属性值放宽点,就org吧。

真蛋疼,出现下面的异常

Caused by: java.lang.IllegalArgumentException: @EnableAsync annotation metadata was not injected

这异常网上一搜就有解决办法:你在beans.xml中的浏览包不能是org.springframework,你可以变成org..…都行。
可是我不想改包名了。怎么办? 我想到了context:include-filter,嗯,我尝试写了下面的配置

<context:component-scan base-package="org" use-default-filters="false">
        <context:include-filter type="regex" expression="org.service.*"/>
        <context:include-filter type="regex" expression="org.persistent.impl*"/>
</context:component-scan>

发现又报错了,说注入的时候在IOC容器中找不到beanDefine,额,意思也就是说,我使用@Repository 的类,没有将信息放到IOC中。这导致的原因是我的context:include-filter没有匹配到这个org.persistent.impl包下的类中

很无语,这样的错误让我如何查资料? 无奈,自能看源码了,一步一步debug。在看源码的时候突然发现自己对context:component-scan认识还真是太少了。

读源码的收获

1、base-package=”org”,spring会项目中所有org包下的类,包括jar

2、use-default-filters=”false” 想用自己的匹配方式,那么一定不能忽略了这个false,这样才能执行下面设置好的过滤方式,否则还是使用默认的规则

3、context:include-filter type=”regex” 的匹配方式是这样子的:第一步找到的所有org下的类,与expression匹配,不管你是不是设置了@Compont 这种注解,而是按照我的匹配规则来,如果按照默认的扫描规则,它是对找到@Compont注解的类的。

说的第三条,我满脸都是泪,写一段代码老是用bug来打击我,我做了上面的配置以后
在org.persistent.impl包下还存在一个BasticDAO类,里面有下面的反射处理

public BasticDAO() {
        entityClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}

照我第三条描述,上面的配置,会匹配BasticDAO,然后在IOC存放一个beanDefine的对象(这个类的信息),然后通过反射实例化这个Bastic,那么泛型的具体类型就不会指定,从而导致错误,正常的能执行应该是

public class UserDAO extends BasticDAO<User> implements IUserDAO{

具体实例化UserDAO, 在BasticDAO中就指定了泛型参数对象为User

我的解决办法是,重写建一个包,存放BasticDAO,我不和你玩了,我和org.persistent.impl包下的小伙伴一起玩

那么上面的代码到底出了什么问题,调试了以后才发现,我正则写错了,这样写是不会匹配到的。

org.persistent.impl*

对于org.persistent.impl 星号后面是对多个l,这样的包名才起作用,而这里面 . 在正则中表示任意的一个字符串,所以,应该写成

<context:include-filter type="regex" expression="org.persistent.impl.*"/>

星号表示,多个 . 就是impl 后面有多个任意的字符串组成,这样才能匹配我期望的包。

呵,最后谈谈maven的学习吧,说到这个maven,非常不习惯它开发代码方式,通过自己一点一点写,也慢慢的理解了一些东西
1、多个模块中,如果一个模块依赖了另外一个模块,你完全可以使用所依赖的那个模块的配置文件
比如,我service模块什么spring配置文件都没有,我使用单元测试的时候,做了如下配置

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration("classpath:config/spring-persistent-test.xml") 
@TransactionConfiguration(transactionManager="transactionManager",defaultRollback=true)
@Transactional
public class UserServiceTest {

    @Resource(name="userService")
    private IUserService userService;

    @Test
    public void exampleForUesrOperation() {
        userService.exampleForUesrOperation(new String[] {"username","userid"}, new String[] {"username"}, new String[] {"username", "userage"}, 
                    new Object[] {"updateService",1}, new Object[] {"superman"}, new Object[] {"testServiceForSpring", "20"});
    }
}

注意一下
@ContextConfiguration("classpath:config/spring-persistent-test.xml")
这里竟然在classpath中找到了这个测试的xml,我在想应该是service依赖了dao模块,就会在classpath中找到dao的配置文件

2、pom.xml中dependencyManagement、还有pluginManagement,这种带Management是在父pom中定义,设定具体版本,在子模块中引用这些定义好的东西

3、pom.xml中为什么要设置plugins? 我之前很不理解,我不设置一样可以用。后面好像明白了,这样的作用是,我可以不使用plugins一些默认的配置,我通过设置plugins 增加对该插件的一些自定义的设置,那么在执行maven这些设置过的插件的时候,就可以往我设置到的方向走

存在多个context:component-scan

如果存在多个context:component-scan,那么按照匹配的规则读取指定的扫描路径的类,封装成BeanDefinition 存放到IOC中。
如我的项目中使用了springmvc,那么存在一个扫描路径

<context:component-scan base-package="org.controller" />

还存在一个spring的基本的扫描路径

<context:component-scan base-package="org" use-default-filters="false">
        <context:include-filter type="regex" expression="org.service.*"/>
        <context:include-filter type="regex" expression="org.persistent.impl.*"/>
</context:component-scan>

其实也是一样,加载到springmvc的配置文件,那么根据springmvc配置的context:component-scan的包路径,读取注解下的class封装成BeanDefinition,存放到IOC中,加载第二个配置文件的context:component-scan,那么根据正则读取匹配的class,存放到IOC中

我试了一下,我在一个配置文件下,用正则匹配扫描路径

<context:component-scan base-package="org" use-default-filters="false">
        <context:include-filter type="regex" expression="org.service.*"/>
        <context:include-filter type="regex" expression="org.persistent.impl.*"/>
        <context:include-filter type="regex" expression="org.action.controller.*"/>
</context:component-scan>

这样也是可行的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值