尽管配置中定义了不正确的BEAN属性名称,Spring如何检测正确的方法名称



如果问题还不够清楚,我的歉意,但我将尝试在下面进行解释:

我有一个称为 cricketcoach.java 的类

public class CricketCoach implements Coach {
  private FortuneService fortuneService;
  ......
  ......
  public void setFortunaeService(FortuneService fortuneService) {
    System.out.println("Spring calling the setter method");
    this.fortuneService = fortuneService;
  }
  .......
  .......
}

我在 applicationContext.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/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">
    <bean
        id = "myFortuneService"
        class = "com.example.basicspring.dependencyinjection.HappyFortuneService">
    </bean>
    <bean
        id = "myCricketCoach"
        class = "com.example.basicspring.dependencyinjection.CricketCoach">
        <property name="fortuneService" ref="myFortuneService"/>
    </bean>
</beans>

我有以下驱动程序类

public class HelloSpringApp {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        Coach theCoach = classPathXmlApplicationContext.getBean("myCricketCoach", Coach.class);
        System.out.println(theCoach.getDailyWorkout());
        System.out.println(theCoach.getDailyFortune());
        classPathXmlApplicationContext.close();
    }
}

applicationContext.xml 中,我故意给出了错误的属性名称,以查看Spring抛出的例外。

以下例外是由弹簧抛出的

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myCricketCoach' defined in class path resource [applicationContext.xml]: Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'fortuneService' of bean class [com.example.basicspring.dependencyinjection.CricketCoach]: Bean property 'fortuneService' is not writable or has an invalid setter method. Did you mean 'fortunaeService'? // Interestingly Spring guesses the correct method name

这里有趣的是,春天猜测实际的方法名称正确,并建议此Did you mean 'fortunaeService'?

但是,当我更改 cricketcoach 类中的方法名称时,从 setFortunaeServicesetXYZ

public void setXYZ(FortuneService fortuneService) {
        System.out.println("Spring calling the setter method");
        this.fortuneService = fortuneService;
    }

春季不再能够猜测正确的方法并显示以下错误消息

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myCricketCoach' defined in class path resource [applicationContext.xml]: Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'fortuneService' of bean class [com.example.basicspring.dependencyinjection.CricketCoach]: Bean property 'fortuneService' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?

我想知道的是Spring如何能够准确地猜测属性名称,但不能第二次这样做。

Spring背后的逻辑到底是什么才能正确猜出该方法的名称?

感谢您的时间

逻辑(至少在我正在查看的春季版本中(可以在课堂上找到:

org.springframework.beans.propertymatches

/**
 * Generate possible property alternatives for the given property and
 * class. Internally uses the <code>getStringDistance</code> method, which
 * in turn uses the Levenshtein algorithm to determine the distance between
 * two Strings.
 * @param propertyDescriptors the JavaBeans property descriptors to search
 * @param maxDistance the maximum distance to accept
 */
private String[] calculateMatches(PropertyDescriptor[] propertyDescriptors, 
       int maxDistance) {
    List<String> candidates = new ArrayList<String>();
    for (PropertyDescriptor pd : propertyDescriptors) {
        if (pd.getWriteMethod() != null) {
            String possibleAlternative = pd.getName();
            if (calculateStringDistance(this.propertyName, possibleAlternative) 
                      <= maxDistance) {
                candidates.add(possibleAlternative);
            }
        }
    }
    Collections.sort(candidates);
    return StringUtils.toStringArray(candidates);
}

正如评论所指出的那样,使用以下算法进行替代方案:

https://en.wikipedia.org/wiki/levenshtein_distance

和setxyz将太远而无法考虑。

最新更新