本文的目的是介绍ioc解析import标签的详细情况,特别关注ioc源码解析的相关信息。我们将通过专业的研究、有关数据的分析等多种方式,为您呈现一个全面的了解ioc解析import标签的机会,同时也不
本文的目的是介绍ioc 解析 import 标签的详细情况,特别关注ioc源码解析的相关信息。我们将通过专业的研究、有关数据的分析等多种方式,为您呈现一个全面的了解ioc 解析 import 标签的机会,同时也不会遗漏关于**@Import({AutoConfigurationImportSelector.class})、10. 组件注册-@Import-使用ImportBeanDefinitionRegistrar、10、组件注册-@Import-使用ImportBeanDefinitionRegistrar、4.2 spring-import 标签的解析;的知识。
本文目录一览:- ioc 解析 import 标签(ioc源码解析)
- **@Import({AutoConfigurationImportSelector.class})
- 10. 组件注册-@Import-使用ImportBeanDefinitionRegistrar
- 10、组件注册-@Import-使用ImportBeanDefinitionRegistrar
- 4.2 spring-import 标签的解析;
ioc 解析 import 标签(ioc源码解析)
importBeanDefinitionResource 方法
/**
* Parse an "import" element and load the bean definitions
* from the given resource into the bean factory.
* 用来解析spring配置文件中的import标签
* 如<import resource="spring-dao.xml"/>
* <import resource="spring-consumer.xml"/>
* 过程如下:
* 获取 source 属性的值,该值表示资源的路径
* 解析路径中的系统属性,如”${user.dir}”
* 判断资源路径 location 是绝对路径还是相对路径
* 如果是绝对路径,则调递归调用 Bean 的解析过程,进行另一次的解析
* 如果是相对路径,则先计算出绝对路径得到 Resource,然后进行解析
* 通知监听器,完成解析
*/
protected void importBeanDefinitionResource(Element ele) {
// 获取 resource 的属性值
String location = ele.getAttribute(RESOURCE_ATTRIBUTE);
// 为空直接退出
if (!StringUtils.hasText(location)) {
getReaderContext().error("Resource location must not be empty", ele);
return;
}
// Resolve system properties: e.g. "${user.dir}"
// 解析系统属性 格式如:"${user.dir}"
location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);
Set<Resource> actualResources = new LinkedHashSet<>(4);
// Discover whether the location is an absolute or relative URI
// 判断 location 是绝对路径还是相对路径
boolean absoluteLocation = false;
try {
// 以classpath*: 或者 classpath:开头,能够通过localtion构建出java.net.URL,判断为绝对路径
absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();
}
catch (URISyntaxException ex) {
// cannot convert to an URI, considering the location relative
// unless it is the well-known Spring prefix "classpath*:"
}
// Absolute or relative?
// 绝对路径
if (absoluteLocation) {
try {
// 直接根据地址加载相应的配置文件
int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources);
if (logger.isDebugEnabled()) {
logger.debug("Imported " + importCount + " bean definitions from URL location [" + location + "]");
}
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error(
"Failed to import bean definitions from URL location [" + location + "]", ele, ex);
}
}
else {
// No URL -> considering resource location as relative to the current file.
// 相对路径,根据相应的地址计算出绝对路径
try {
int importCount;
Resource relativeResource = getReaderContext().getResource().createRelative(location);
if (relativeResource.exists()) {
importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
actualResources.add(relativeResource);
}
else {
String baseLocation = getReaderContext().getResource().getURL().toString();
importCount = getReaderContext().getReader().loadBeanDefinitions(
StringUtils.applyRelativePath(baseLocation, location), actualResources);
}
if (logger.isDebugEnabled()) {
logger.debug("Imported " + importCount + " bean definitions from relative location [" + location + "]");
}
}
catch (IOException ex) {
getReaderContext().error("Failed to resolve current resource location", ele, ex);
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to import bean definitions from relative location [" + location + "]",
ele, ex);
}
}
// 解析成功后,进行监听器激活处理
Resource[] actResArray = actualResources.toArray(new Resource[0]);
getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));
}
**@Import({AutoConfigurationImportSelector.class})
:**将**AutoConfigurationImportSelector**这个类导入到spring容器中,**AutoConfigurationImportSelector**可以帮助springboot应用将所有符合条件的@Configuration配置都加载到当前SpringBoot创建并使用的IoC容器(ApplicationContext)中 继续研究**AutoConfigurationImportSelector**这个类,通过源码分析这个类中是通过selectImports这个方法告诉springboot都需要导入那些组件:  **深入研究loadMetadata方法**  **深入getCandidateConfigurations方法** 个方法中有一个重要方法loadFactoryNames,这个方法是让SpringFactoryLoader去加载一些组件的名字。  继续点开loadFactory方法 ```java public static List loadFactoryNames(Class factoryClass, @Nullable ClassLoader classLoader) { //获取出入的键 String factoryClassName = factoryClass.getName(); return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList()); } private static Map> loadSpringFactories( @Nullable ClassLoader classLoader) { MultiValueMap result = (MultiValueMap)cache.get(classLoader); if (result != null) { return result; } else { try { 这些内容,是从拉勾教育的《Java工程师高薪训练营》里学到的,课程内容非常全面,还有拉勾的内推大厂服务,推荐你也看看。10. 组件注册-@Import-使用ImportBeanDefinitionRegistrar
用户自定义的类实现ImportBeanDefinitionRegistrar接口,可以在registerBeanDefinitions函数中手动的将一个组件注册到容器中,代码如下:
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { /** * * @param importingClassMetadata 当前类的注解信息 * @param registry BeanDefinition注册类 * 把所需要添加到容器中的bean,调用BeanDefinitionRegistry.registerBeanDefinition手工注册进来 */ @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { boolean definition = registry.containsBeanDefinition("io.scnb.bean.Red"); boolean definition2 = registry.containsBeanDefinition("io.scnb.bean.Blue"); if (definition && definition2) { // 指定bean定义信息(Bean的类型,scope等) RootBeanDefinition beanDefinition = new RootBeanDefinition(RainBow.class); registry.registerBeanDefinition("rainBow", beanDefinition); } } }
在使用时,需要在@Import注解的值中指明使用该实现了ImportBeanDefinitionRegistrar接口的类:
@Configuration @Import({Color.class, Red.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class}) public class MainConfig2 {}
测试代码:
@Test public void testImport() { printBeans(context); } public void printBeans(AnnotationConfigApplicationContext context) { String[] beanDefinitionNames = context.getBeanDefinitionNames(); for (String name : beanDefinitionNames) { System.out.println(name); } }
测试代码输出结果:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig2
io.scnb.bean.Color
io.scnb.bean.Red
io.scnb.bean.Blue
io.scnb.bean.Yellow
person
steve
rainBow
10、组件注册-@Import-使用ImportBeanDefinitionRegistrar
10、组件注册-@Import-使用ImportBeanDefinitionRegistrar
public interface ImportBeanDefinitionRegistrar {
/**
* Register bean definitions as necessary based on the given annotation metadata of
* the importing {@code @Configuration} class.
* <p>Note that {@link BeanDefinitionRegistryPostProcessor} types may <em>not</em> be
* registered here, due to lifecycle constraints related to {@code @Configuration}
* class processing.
* @param importingClassMetadata annotation metadata of the importing class
* @param registry current bean definition registry
*/
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);
}
10.1 实现ImportBeanDefinitionRegistrar 并重写 registerBeanDefinitionsfan方法
package com.hw.springannotation.conditional;
import com.hw.springannotation.beans.RainBow;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
/**
* @Description TODO
* @Author hw
* @Date 2018/11/28 16:16
* @Version 1.0
*/
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/**
* @param importingClassMetadata annotation metadata of the importing class 当前类的注解信息
* @param registry current bean definition registry 定义的注册类
* 所有需要添加到容器中的bean BeanDefinitionRegistry.registerBeanDefinition 手动注册进来
*/
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean red = registry.containsBeanDefinition("com.hw.springannotation.beans.Red");
boolean blue = registry.containsBeanDefinition("com.hw.springannotation.beans.Blue");
if (red && blue) {
// 指定Bean的定义信息,Bean的类型,作用域等
BeanDefinition beanDefinition = new RootBeanDefinition(RainBow.class);
// 注册一个Bean,指定bean名
registry.registerBeanDefinition("rainBow", beanDefinition);
}
}
}
10.2 使用
新建RainBow类,并在MainConfig中导入MyImportBeanDefinitionRegistrar.class
@Import({Color.class, Red.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
10.3 测试
4.2 spring-import 标签的解析;
对于 spring 配置文件的编写,我想,对于经历过庞大项目的人,都有那种恐惧的心理,太多的配置文件。不过,分模块都是大多数人能想到的方法,但是,怎么分模块,那就是仁者见仁,智者见智了。我的策略是使用 import。
基本代码格式如下
web.xml
<?xml version="1.0" encoding="gb2312"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<import resource="CTIContext.xml" />
<import resource="customerContext.xml" />
<import resource="customerServingContext.xml" />
<import resource="manageContext.xml" />
<import resource="routineContext.xml" />
<import resource="systemContext.xml" />
</beans>
1 /**
2 * Parse an "import" element and load the bean definitions from the given resource
3 * into the bean factory.
4 */
5 protected void importBeanDefinitionResource(Element ele) {
6 // 获取resource 属性
7 String location = ele.getAttribute(RESOURCE_ATTRIBUTE);
8 // 如果不存在resource ,则不做任何处理
9 if (!StringUtils.hasText(location)) {
10 getReaderContext().error("Resource location must not be empty", ele);
11 return;
12 }
13
14 // Resolve system properties: e.g. "${user.dir}"
15 // 解析系统属性.格式如 : ${user.dir}
16 location = environment.resolveRequiredPlaceholders(location);
17
18 Set<Resource> actualResources = new LinkedHashSet<Resource>(4);
19
20 // Discover whether the location is an absolute or relative URI
21 // 判断是绝对地址还是相对地址
22 boolean absoluteLocation = false;
23 try {
24 absoluteLocation = ResourcePatternUtils.isUrl(location)
25 || ResourceUtils.toURI(location).isAbsolute();
26 }
27 catch (URISyntaxException ex) {
28 // cannot convert to an URI, considering the location relative
29 // unless it is the well-known Spring prefix "classpath*:"
30 }
31
32 // Absolute or relative?
33 // 如果是绝对地址,则直接根据地址加载对应的配置文件
34 if (absoluteLocation) {
35 try {
36 int importCount = getReaderContext().getReader().loadBeanDefinitions(
37 location, actualResources);
38 if (logger.isDebugEnabled()) {
39 logger.debug("Imported " + importCount
40 + " bean definitions from URL location [" + location + "]");
41 }
42 }
43 catch (BeanDefinitionStoreException ex) {
44 getReaderContext().error(
45 "Failed to import bean definitions from URL location ["
46 + location + "]", ele, ex);
47 }
48 }
49 else {
50 // No URL -> considering resource location as relative to the current file.
51 // 如果是相对地址,则计算出绝对地址
52 try {
53 int importCount;
54 // Resource 的多个子类 ,如 VfsResource,FileSystemResource,ClassPathResource
55 // 而每个Resource的createRelative 方法都不太一样所以这里先使用子类的方法尝试解析,
56 Resource relativeResource = getReaderContext().getResource().createRelative(
57 location);
58 if (relativeResource.exists()) {
59 importCount = getReaderContext().getReader().loadBeanDefinitions(
60 relativeResource);
61 actualResources.add(relativeResource);
62 }
63 else {
64 // 如果解析不成功,则使用默认解析器ResourcePatternResolver 进行解析
65 String baseLocation = getReaderContext().getResource().getURL().toString();
66 importCount = getReaderContext().getReader().loadBeanDefinitions(
67 StringUtils.applyRelativePath(baseLocation, location),
68 actualResources);
69 }
70 if (logger.isDebugEnabled()) {
71 logger.debug("Imported " + importCount
72 + " bean definitions from relative location [" + location
73 + "]");
74 }
75 }
76 catch (IOException ex) {
77 getReaderContext().error("Failed to resolve current resource location",
78 ele, ex);
79 }
80 catch (BeanDefinitionStoreException ex) {
81 getReaderContext().error(
82 "Failed to import bean definitions from relative location ["
83 + location + "]", ele, ex);
84 }
85 }
86 // 解析后进行监听器激活处理
87 Resource[] actResArray = actualResources.toArray(new Resource[actualResources.size()]);
88 getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));
89 }
关于ioc 解析 import 标签和ioc源码解析的问题我们已经讲解完毕,感谢您的阅读,如果还想了解更多关于**@Import({AutoConfigurationImportSelector.class})、10. 组件注册-@Import-使用ImportBeanDefinitionRegistrar、10、组件注册-@Import-使用ImportBeanDefinitionRegistrar、4.2 spring-import 标签的解析;等相关内容,可以在本站寻找。
本文标签: