文章目录
一、component-scan概述
1、Spring中component-scan标签配置
spring5.exercise.demo17.spring.xml
<?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/context
http://www.springframework.org/schema/context/spring-context.xsd
">
<!-- 自定义标签 扫描包 -->
<context:component-scan base-package="com.jd.nlp.dev.muzi.spring5.exercise.demo17" />
</beans>
描述
上述spring.xml配置中,配置了一个component-scan标签,这个标签的作用是扫描项目代码中com.jd.nlp.dev.muzi.spring5.exercise.demo01下的class类,如果有@Service @Controller @Component等注解的类,将这些类解析成一个个的BeanDefinition,容器初始化时会针对这些类去创建实例对象。
2、component-scan功能案例代码
com.jd.nlp.dev.muzi.spring5.exercise.demo17.ProductService
@Service("productService")
public class ProductService {
private String name = "Muzi";
private String well = "开始Spring5的炫酷之旅,(Muzi)书生不读四书五经!";
public void show() {
System.out.println(name + "\n" + well);
}
public ProductService() {
this.name = "无参数构造函数";
}
}
测试容器启动代码
@Test
public void run01(){
// 基于加载XML配置文件的方式,启动spring容器
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath*:spring5.exercise.demo17.spring.xml");
ProductService productService = (ProductService) context.getBean("productService");
productService.show();
}
描述
上述测试代码中,创建了基于解析XML的容器,解析spring5.exercise.demo17.spring.xml配置文件,在配置文件中配置了一个component-scan标签去扫描“com.jd.nlp.dev.muzi.spring5.exercise.demo17”包下面的含有Spring @Component下的类ProductService。
我们测试代码中通过容器获取ProductService的实例,调用show方法。
测试结果
09:54:56.037 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'productService'
无参数构造函数
开始Spring5的炫酷之旅,(Muzi)书生不读四书五经!
那么具体component-scan标签是如何解析的呢?和我跟着源码一点一点阅读吧。
二、component-scan解析源码
1、回顾Spring的自定义标签解析(SPI)
component-scan是一个自定义标签
<context:component-scan base-package="com.jd.nlp.dev.muzi.spring5.exercise.demo17" />
namespace uri是http://www.springframework.org/schema/context
xmlns:context="http://www.springframework.org/schema/context"
所以我们需要去context的jar包去找 spring.handlers文件
spring-context的spring.handlers文件
http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
http\://www.springframework.org/schema/jee=org.springframework.ejb.config.JeeNamespaceHandler
http\://www.springframework.org/schema/lang=org.springframework.scripting.config.LangNamespaceHandler
http\://www.springframework.org/schema/task=org.springframework.scheduling.config.TaskNamespaceHandler
http\://www.springframework.org/schema/cache=org.springframework.cache.config.CacheNamespaceHandler
基于上述文件可知,http://www.springframework.org/schema/context这个namespace uri对应的解析类是“org.springframework.context.config.ContextNamespaceHandler”
在ContextNamespaceHandler的init方法中,component-scan这个自定义标签是ComponentScanBeanDefinitionParser这个解析类来进行解析的。
@Override
public void init() {
// 标签元素和解析类的映射关系
registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
registerBeanDefinitionPar