Spring的autowire-candidate设计 详解Spring的autowire-candidate设计
沉迷Spring 人气:0Xml配置文件中的default-autowire-candidates属性
有的同学对这个配置可能不熟悉或者说都不知道这个配置的存在,那首先我们看下default-autowire-candidates这个配置是放在何处的:
<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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd default-autowire-candidates="service*"> <bean id="serviceA" class="org.wonder.frame.xmlConfig.SetterBean$ServiceA" autowire-candidate="false"/> <bean id="serviceB" class="org.wonder.frame.xmlConfig.SetterBean$ServiceB" /> <bean id="setterBean" class="org.wonder.frame.xmlConfig.SetterBean" autowire="byType" /> </beans>
在idea中我们可以点开 default-autowire-candidates这个属性所在的spring-beans.xsd就能看到官方对这个属性的注释:
A default bean name pattern for identifying autowire candidates: e.g. "Service", "data", "Service", "dataService". Also accepts a comma-separated list of patterns: e.g. "Service,*Dao". See the documentation for the 'autowire-candidate' attribute of the 'bean' element for the semantic details of autowire candidate beans.
简单翻译下也就是说这个属性可以标示配置文件中的所有Bean默认能否成为自动注入候选者的名称匹配模式,比如 "Service", "data", "Service", "dataService".也支持以逗号分隔的字符串模式列表:"Service,Dao". 比如上面配置文件中配置的service\就匹配了serviceA,serviceB两个Bean.但是Spring的设计规定serviceA自身配置的autowire-candidate为false会覆盖default-autowire-candidates配置,所以serviceA是不会成为自动注入的候选者。
匹配逻辑算法
我们深入到源码中看下Spring是如何根据这个匹配模式来与自身bean名称来匹配的
String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE); if ("".equals(autowireCandidate) || DEFAULT_VALUE.equals(autowireCandidate)) { String candidatePattern = this.defaults.getAutowireCandidates(); if (candidatePattern != null) { String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern); bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName)); } } else { bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate)); }
很清楚,在bean本身配置autowire-candidate为空或者默认的情况下,Spring会把default-autowire-candidates字符串转换成数组,然后依赖PatternMatchUtils类的simpleMatch方法来验证当前bean的名称是否匹配,成功与否都会赋值给当前bean的autowireCandidate属性。其实最主要的还是PatternMatchUtils.simpleMatch方法
PatternMatchUtils.simpleMatch
public static boolean simpleMatch(@Nullable String pattern, @Nullable String str) { //pattern 匹配模式为空 或者待匹配字符串为空就返回false if (pattern == null || str == null) { return false; } //找到第一个* 在匹配模式字符串中的的索引 int firstIndex = pattern.indexOf('*'); if (firstIndex == -1) { //索引为空的情况下就代表 模式字符串要和待匹配字符串相等。 return pattern.equals(str); } //*在第一位 if (firstIndex == 0) { //*在第一位 且匹配模式字符串长度为1 那就直接返回true ,比如 * if (pattern.length() == 1) { return true; } //找到下一个*的起始位置 int nextIndex = pattern.indexOf('*', firstIndex + 1); if (nextIndex == -1) { //如果没有*了,就判断 待匹配的字符串是否是以pattern结尾的。 //比如*service Aservice就满足这种情况 return str.endsWith(pattern.substring(1)); } //截取第一个* 和之后一个* 之间的字符串 String part = pattern.substring(1, nextIndex); if (part.isEmpty()) { return simpleMatch(pattern.substring(nextIndex), str); } //str 是指待匹配的字符 int partIndex = str.indexOf(part); while (partIndex != -1) { if (simpleMatch(pattern.substring(nextIndex), str.substring(partIndex + part.length()))) { return true; } //从partIndex+1 开始计算part的索引 partIndex = str.indexOf(part, partIndex + 1); } return false; } //待匹配字符串的长度比 第一个*的索引 大或者相等的情况下 //截取模式字符串 0 到 第一个*号之间的字符串 ,截取 待匹配字符串 0 到 第一个*号之间的字符串 对比 //如果相等 ,再截取 模式字符串 第一个*号之后的字符串 和 待匹配 字符串 第一个*号之后的字符串 去做匹配 return (str.length() >= firstIndex && pattern.substring(0, firstIndex).equals(str.substring(0, firstIndex)) && simpleMatch(pattern.substring(firstIndex), str.substring(firstIndex))); }
这个Utils类的工具函数实现的字符串模糊匹配算法在我们日常开发中对字符串的操作方面也会有或多或少的帮助。
总结
Spring中的很多设计细节总是给我们很多惊喜,从中我们也可以很多小技巧,给我们日常开发会带来不少启发。
加载全部内容