Spring应用上下文配置:混合配置
2016-09-07 22:34
441 查看
前言
所谓Spring应用上下文混合配置,指的是配置一部分在xml文件,一部分在java代码。这种方式不是很常见,常见的要么是纯xml文件配置,要么是纯java编程配置。纯java编程配置后续章节我们会详细讲解。关于这两种纯配置方式的比较,我们前面的章节已经提过。根应用上下文配置
<?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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <context:annotation-config /> <context:component-scan base-package="com.gxz" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Service" /> </context:component-scan> </beans>
配置context:annotation-config,表示注解配置,凡是java实现类做了以下的注解,都被认为是需要Spring管理的bean:@Component、@Service、@Controller、@Repository等。所谓纳入Spring管理的bean,指的是在恰当的时间,Spring将实例化bean并为之注入依赖。配置context:component-scan:表示组件扫描,扫描base-package指定的包及其子包,若这些包中的实现类有注解@Component及其具体注解,都被认为是Spring管理的bean。
配置context:include-filter:表示扫描过滤器,一种包含的过滤器,Spring管理expression指定的bean。上述配置中,expression="org.springframework.stereotype.Service",表示Spring只管理类型为@Service的bean,而忽略其他类型的bean,比如类型为@Component、@Controller、@Repository的bean不纳入Spring的管理。
配置type="annotation":表示过滤器针对实现类的注解。配置use-default-filters="false":表示不再使用默认的过滤器,而是使用自定义过滤器。若是我们使用了包含过滤器或是排除过滤器,那么,一定要配置不再使用默认过滤器。否则,包含过滤器或是排除过滤器的配置无效。包含过滤器的配置是context:include-filter,排除过滤器的配置是context:exclude-filter。关于排除过滤器,接下类的章节我们会详细讲解。
从上述的配置我们可以看出,我们并没有直接配置需要Spring管理哪一个具体的bean,而是通过指定范围扫描注解的方式。在指定的范围内,如果我们希望实现类纳入Spring管理,我们需要在实现类加上注解@Component及其具体注解。这需要在xml文件配置,需要在java实现类配置(java编程配置),所以,此种配置方式称之为混合配置。
通常情况下,我们创建一个根应用上下文和一个DispatcherServlet应用上下文,根应用上下文管理一组和业务逻辑相关
4000
的bean,而DispatcherServlet应用上下文管理一组和控制相关的bean。所以,在配置根应用上下文是,我们使用了包含过滤器,让Spring只管理类型为@Service的bean。
DispatcherServlet应用上下文配置
<?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:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"> <mvc:annotation-driven /> <context:annotation-config /> <context:component-scan base-package="com.gxz" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" /> </context:component-scan> </beans>
业务逻辑相关的bean
package com.gxz; import org.springframework.stereotype.Service; @Service public class StudentImp implements Student { @Override public String sayHi(String name) { return "Hi," + name; } public StudentImp() { super(); System.out.println("StudentImp()"); } }
package com.gxz;
public interface Student {
String sayHi(String name);
}
控制器bean
package com.gxz; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class StudentController { @Autowired private Student student; @ResponseBody @RequestMapping("/") public String sayHi() { return "Hi!"; } @ResponseBody @RequestMapping(value="/say", params="name") public String say(@RequestParam("name") String name) { return student.sayHi(name); } public void setStudent(Student student) { this.student = student; } public StudentController() { super(); System.out.println("StudentController()"); } }
注解@Autowired:表示Spring在实例化bean StudentController时,为之注入依赖Student,所谓的依赖Student,就是一个实现了Student接口的实现类,它必须是一个bean。可以看出,这个依赖就是bean StudentImp。依赖必须是唯一的,如果实现接口Student的实现类有两个,分别是StudentImp、ComputerStudent,并且这两个实现类都是受Spring管理的bean,那么,Spring会报出异常,信息如下所示。
package com.gxz; import org.springframework.stereotype.Service; @Service public class ComputerStudent implements Student { public String sayHi(String name) { return "Hi, " + name + ".Happy to see again."; } }
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'studentController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.gxz.Student com.gxz.StudentController.student; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.gxz.Student] is defined: expected single matching bean but found 2: computerStudent,studentImp Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.gxz.Student com.gxz.StudentController.student; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.gxz.Student] is defined: expected single matching bean but found 2: computerStudent,studentImp Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.gxz.Student] is defined: expected single matching bean but found 2: computerStudent,studentImp若要解决这个异常,就必须告诉Spring,Spring在实例化bean StudentController时,为之注入依赖Student时明确指定是哪一个bean(computerStudent,studentImp二选一)。
@Autowired @Qualifier("computerStudent") private Student student;
配置@Qualifier:指定注入的依赖是computerStudent,而不是studentImp。Spring实例化bean,默认取名为类名的骆驼命名。比如实现类StudentImp,作为bean实例化后取名为studentImp,实现类ComputerStudent取名为computerStudent,实现类StudentController取名为studentController。
现在有这样一种场景,实现类为com.gxz.StudentImp作为bean实例化后,默认取名为studentImp,实现类com.gxz.config.StudentImp作为bean实例化后取名为studentImp,这就导致bean名字重复,Spring报出如下异常。
org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from ServletContext resource [/WEB-INF/rootContext.xml]; nested exception is org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'studentImp' for bean class [com.gxz.StudentImp] conflicts with existing, non-compatible bean definition of same name and class [com.gxz.config.StudentImp] Caused by: org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'studentImp' for bean class [com.gxz.StudentImp] conflicts with existing, non-compatible bean definition of same name and class [com.gxz.config.StudentImp]
为了解决上述问题,需要在配置实现类为bean时,为之指定实例化后的名字,以作区别。
package com.gxz.config; import org.springframework.stereotype.Service; import com.gxz.Student; @Service("configStudentImp") public class StudentImp implements Student { public String sayHi(String name) { return "Hi, " + name + ".Happy to see again."; } }
上述代码实现类com.gxz.config.StudentImp作为bean实例化后,取名为configStudentImp。我们知道,实现类com.gxz.StudentImp作为bean实例化后,默认取名为studentImp,这样一来,二者的名字便不再重复。
以下注解和@Autowired的用法和作用等价:@Inject、@Resource。其中,@Autowired的全称为org.springframework.beans.factory.annotation.Autowired,@Inject的全称是javax.inject.Inject,@Resource的全称是javax.annotation.Resource。
以下注解和@Qualifier的用法和作用等价:@Named。其中,@Qualifier的全称是org.springframework.beans.factory.annotation.Qualifier,@Named的全称是javax.inject.Named。
注解@Autowired配置的位置
到目前为止,注解@Autowired配置的位置一直在字段上。实际上,它可以位于字段的set方法上,也可以在构造函数上,该构造函数的参数之一是字段。private Student student; @Autowired public void setStudent(Student student) { this.student = student; }
上述代码在set方法上告诉Spring注入依赖student。
private Student student; @Autowired public StudentController(Student student) { super(); this.student = student; System.out.println("StudentController() with argument."); }
上述代码在构造方法上告诉Spring注入依赖。默认情况下,Spring实例化bean时,调用的是bean的默认构造函数,即无参构造函数。但是,若是有构造函数被备注为@Autowired,那么,Spring将调用该@Autowired构造函数。因为,Spring需要调用@Autowired构造函数为bean注入依赖。
注意,一个bean不能有两个或以上的@Autowired构造函数,否则,Spring不知要调用哪个构造函数, 报出如下异常。
@Autowired public StudentController(Student student) { super(); this.student = student; System.out.println("StudentController() with argument student."); } @Autowired public StudentController( Teacher teacher) { super(); this.teacher = teacher; System.out.println("StudentController() with arguments teacher."); }
org.springframework.beans.factory.BeanCreationException: Invalid autowire-marked constructor: public com.gxz.StudentController(com.gxz.Student). Found another constructor with 'required' Autowired annotation: public com.gxz.StudentController(com.gxz.Student,com.gxz.Teacher)
关于排除过滤器存在的问题
上面我们已经提过排除过滤器,现在谈一谈它存在的问题。我们有这样的场景,根应用上下文管理一组和业务逻辑相关的bean,也就是说,控制器bean需要被排除。<?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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <context:annotation-config /> <context:component-scan base-package="com.gxz" use-default-filters="false"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" /> </context:component-scan> </beans>
上述配置说明,根应用上下文排除控制器bean。但是,根据测试结果,上述配置排除了所有bean。也就是说,包com.gxz及其子包所有的bean都被排除。显然,这不是我们想要的结果。若是我们把use-default-filters设置为true,结果不排除任何bean。也就是说,包com.gxz及其子包所有的bean都纳入Spring管理,这也不是我们想要的结果。因此,我们要慎重使用排除过滤器,因为它总是没有达到我们的期望。
相关文章推荐
- Java后台框架篇--Spring应用上下文配置:Xml方式
- Spring应用上下文配置:xml配置
- Spring应用上下文配置:java编程配置
- 通过上下文路径得到在spring配置文件中所定义的bean
- spring2.0配置中的新标签应用
- Struts2+Hibernate3.2+Spring 2.0整合应用配置
- Hibernate和ibatis在同一个webapp中混合使用在spring中的配置方法
- (转载)Spring数据源的灵活配置巧应用
- Spring bean配置中属性值由String到实际类型的动态转化过程及PropertyEditor类的应用
- Spring数据源的灵活配置巧应用
- Spring配置上下文路径的技巧
- Spring学习文档_IOC配置与应用
- spring2.0配置中的新标签应用
- Spring 数据源配置与应用
- Spring数据源的灵活配置巧应用
- Spring quartz 应用配置
- Hibernate和ibatis在同一个webapp中混合使用在spring中的配置方法
- Spring 数据源配置与应用
- Spring基于注解的缓存配置--web应用实例
- spring3 混合使用 XML 与注解(Annotation)进行 Bean 的配置