@ComponentScan注解用法之包路径占位符解析

@ComponentScan注解用法之包路径占位符解析,博智网带你了解详细信息 。
目录

  • 代码测试
  • 底层行为分析
  • 总结

@ComponentScan注解的basePackages属性支持占位符吗?
答案是肯定的 。
代码测试首先编写一个属性配置文件(Properties),名字随意,放在resources目录下 。
在该文件中只需要定义一个属性就可以,属性名随意,值必须是要扫描的包路径 。
【@ComponentScan注解用法之包路径占位符解析】basepackages=com.xxx.fame.placeholder
编写一个Bean,空类即可 。
package com.xxx.fame.placeholder;import org.springframework.stereotype.Component;@Componentpublic class ComponentBean {}
编写启动类,在启动类中通过@PropertySource注解来将外部配置文件加载到Spring应用上下文中,其次在@ComponentScan注解的value属性值中使用占位符来指定要扫描的包路径(占位符中指定的属性名必须和前面在属性文件中定义的属性名一致) 。
使用Spring 应用上下文来获取前面编写的Bean,执行main方法,那么是会报错呢?还是正常返回实例呢?
package com.xxx.fame.placeholder;import org.springframework.context.annotation.AnnotationConfigApplicationContext;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.PropertySource;@PropertySource("classpath:componentscan.properties")@ComponentScan("${basepackages}")public class ComponentScanPlaceholderDemo {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();context.register(ComponentScanPlaceholderDemo.class);context.refresh();ComponentBean componentBean = context.getBean(ComponentBean.class);System.out.println(componentBean);}}
运行结果如下,可以看到正常返回ComponentBean在IoC容器中的实例了 。
@ComponentScan注解用法之包路径占位符解析


@ComponentScan注解用法之包路径占位符解析


@ComponentScan注解用法之包路径占位符解析


@ComponentScan注解用法之包路径占位符解析


@ComponentScan注解用法之包路径占位符解析


@ComponentScan注解用法之包路径占位符解析



AbstractProperyResolver实现了resolvePlaceholders方法以及resolveRequiredPlaceholders方法,不过能明显看到都是委派给PropertyPlaceholderHelper类来完成占位符的解析 。不过重点是在通过cr-eatePlaceholders方法创建PropertyPlaceholderHelper实例传入的布尔值 。
在resolvePlaceholders方法中调用createPlaceholderHelper方法时,传入的布尔值为true,而在resolveRequiredPlaceholders方法中调用createPlaceholders方式时传入的布尔值为false 。
该值决定了PropertyPlaceholderHelper在面对无法解析的占位符时的行为 。
@Nullableprivate PropertyPlaceholderHelper nonStrictHelper; @Nullableprivate PropertyPlaceholderHelper strictHelper;// AbstractPropertyResolver#resolvePlaceholderspublic String resolvePlaceholders(String text) {if (this.nonStrictHelper == null) {this.nonStrictHelper = createPlaceholderHelper(true);}return doResolvePlaceholders(text, this.nonStrictHelper);}// AbstractPropertyResolver#resolveRequiredPlaceholderspublic String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {if (this.strictHelper == null) {this.strictHelper = createPlaceholderHelper(false);}return doResolvePlaceholders(text, this.strictHelper);}
在PropertyPlaceholderHelper的parseStringValue方法中(该方法就是Spring 应用上下文中解析占位符的地方(例如@Value注解中配置的占位符)) 。
在该方法中,对于无法解析的占位符,首先会判断ignoreUnresolvablePlaceholders属性是否为true,如果为true,则继续尝试解析,否则(else分支)就是抛出我们前面的看到的异常 。
ingnoreUresolvablePlaceholder属性的含义是代表是否需要忽略不能解析的占位符 。
// PropertyPlaceholderHelper#parseStringValueprotected String parseStringValue(String value, PlaceholderResolver placeholderResolver, @Nullable Set<String> visitedPlaceholders) {// 省略与本次分析无关代码......StringBuilder result = new StringBuilder(value);while (startIndex != -1) {int endIndex = findPlaceholderEndIndex(result, startIndex);if (endIndex != -1) {// 省略与本次分析无关代码......} else if (this.ignoreUnresolvablePlaceholders) {// Proceed with unprocessed value.startIndex = result.indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.length());} else {throw new IllegalArgumentException("Could not resolve placeholder '" +placeholder + "'" + " in value \"" + value + "\"");}visitedPlaceholders.remove(originalPlaceholder);} else {startIndex = -1;}}return result.toString();}

推荐阅读