计算机知识

当前位置:澳门新葡萄京 > 计算机知识 > 而是懒的代名词

而是懒的代名词

来源:http://www.hhmtch.com 作者:澳门新葡萄京 时间:2019-05-30 04:41

["

n 大家好,我是磊叔的猪弟,猪在我心中从来不是蠢的代名词,而是懒的代名词,本次准备记录一个在n n 开发nn n 测试nn 过程中遇到的问题,跟踪了三天n n springnn 和第三方RPC组件的n n 源码nn ,最终发现了问题是因为第三方组件没有处理好而父子容器导致的,还有一个因素是spring注解扫描重叠。n

n

Spring版本:4.3.13.RELEASEnIDE工具:IDEA 2017.2.6nJDK版本:1.7_u25 64位n

n

n 在n n n SpringMVCn nn
n 的n n 配置nn 中为了防止Spring重复创建同一个类的n n 实例nn ,一般会用到n n <context:component-scan>nn
n 的两个子标签n n <context:include-filter>&&<context:exclude-filter>nn
n 。n

n

n 但它使用的时候表现的效果并不是和语义上的完全一致,现在来看一下其中的坑:n

n

n 在很多配置中一般都会把n n spring-config.xmlnn
n 和n n spring-mvc.xmlnn
n 进行分开配置,这种配置可以他们保证各司其职,在n n webnn .xml的一般配置中n n spring-mvc.xmlnn
n 实例创建初始化是以n n DispatchServletnn
n 为入口,而n n spring-config.xmlnn
n 实例创建初始化是以n n ContextLoadListenernn
n 为入口的,容器的加载顺序:n n n listn n ener -> filter ->n n servletn nn
n ,所以spring容器先初始化,springmvc容器后初始化 。n

n

<!--spring 入口-->n    <context-param>n        <param-name>contextConfigLocation</param-name>n        <param-value>n            classpath:spring-config.xmln        </param-value>n    </context-param>n    <listener>n        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>n    </listener>nn    <!--spring mvc 入口-->n    <servlet>n        <servlet-name>blog-spring-mvc</servlet-name>n        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>n        <init-param>n            <param-name>contextConfigLocation</param-name>n            <param-value>n                classpath:spring-mvc.xmln            </param-value>n        </init-param>n        <load-on-startup>1</load-on-startup>n    </servlet>n    <servlet-mapping>n        <servlet-name>blog-spring-mvc</servlet-name>n        <url-pattern>/</url-pattern>n    </servlet-mapping>

n

n 如果在n n spring-mvc.xmlnn
n 中配置扫描的包和n n spring-config.xmlnn
n 中的发生重叠,那么会导致一个n n beannn 被创建两次,而且在n n springnn
n 中是存在父子容器的,n n springnn
n 容器是父容器,n n springmvcnn
n 是子容器,n n springmvcnn
n 创建的实例放在子容器中,n n springnn
n 创建的实例放在父容器中。n

n

n 其实这同一个类的两个实例是不同的,n n springmvcnn
n 创建实例默认对象不实现接口(大家都知道Controller是不用实现接口的),所以springmvc创建的实例是直接使用目标类的构造器来实例化的,而不是代理对象,即使一个类实现了接口,但如果该类是由springmvc实例化,那么springmvc也会直接使用该类的构造器直接创建一个对象(怎么去证明呢,你可以写一个定时任务,在定时任务中注入Controller的实例,然后den n bugnn 查看实例对象的地址,如果是代理对象在地址上都会有一个$Proxy的标记,否则就不是代理对象),所以在controller层使用n n AOPnn 时多数采用的是CGLIB子类代理。n

n

n Spring创建实例会判断目标类是否实现了接口,如果没实现接口那么就直接采用目标类构造器创建,像一般的service和dao都会采用接口方式编程,对于接口方式编程的类,spring创建的实例都是代理对象(这一点可以用debug的方式查看controller类中注入的service实例对象地址,他们都带有一个$Proxy的标记,很容易就能看出都是代理对象)。n

n

n 那么为了防止重叠我们要把重叠的部分去掉,现在有下面的一个n n 需求nn :n

n

n 在n n spring-mvc.xmlnn
n 中只对工程中所有用n n @Controllernn
n 注解的类进行扫描创建实例。n

n

n 在n n spring-config.xmlnn
n 中要对工程中所有的非n n @Controllernn
n 注解的类进行扫描创建实例。n

n

n 现在给定一个项目的包结构:n

n

n n xin.sun.blog.controlllernn

n

n n xin.sun.blog.servicenn

n

n (1)在n n spring-mvc.xmlnn
n 中有以下配置:n

n

<!-- 只扫描 @Controller注解-->n<context:component-scanbase-package="xin.sun.blog.controlller">n    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>n</context:component-scan>

n

n 可以看出要把最后的包写上,不能包含子包,所以不能写成:n n base-package="xin.sun.blog"nn
n 。如果这样写,对于n n include-filternn
n 标签来讲它会扫描基包下面所有spring注解的类,而不是仅仅扫描n n @Controllernn
n 。这点需要非常的注意,这一般会导致一个常见的错误,那就是事务不起作用,补救的方法是添加n n use-default-filters="false"nn
n 。n

n

n (2)在n n spring-config.xmlnn
n 中有如下配置:n

n

<!-- 配置扫描注解,不扫描 @Controller注解-->n<context:component-scan base-package="xin.sun.blog">n    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>n</context:component-scan>

n

n 可以看到,他是要扫描n n xin.sun.blognn
n 包和子包下的所有spring注解的类,但是不包含n n @Controllernn
n 注解的类。对于exculude-filter不存在包不精确导致都进行扫描的问题。n

n

n 那么还有一个问题:当扫描的包不小心重叠了,导致类在父子容器各实例化了一遍,在n n @Autowirenn
n 的时候会注入哪个容器中的对象呢?看一个Controller类,n n 代码nn 如下:n

n

@Controllernpublic class MyController{nn    @Autowiredn    private IValidService validService;n    //其他代码省略 n}

n

n 答案是:Spring为了保证注入类的n n 一致性nn ,采用了双亲委托的机制,如果父容器中存在该类的实例那么优先使用父容器中的实例,如果父容器中没有该实例才会用子容器中的实例n

","原文地址:【SpringMVC】<context:include-filter>&&<context:excl, 感谢原作者分享。"]

本文由澳门新葡萄京发布于计算机知识,转载请注明出处:而是懒的代名词

关键词: bug http Spring App classpath

上一篇:jquery之获取select选中的值

下一篇:没有了