#java #spring
#java #spring
Вопрос:
Я работаю над экспериментальным методом, который примет имя компонента, имя свойства и выражение значения и использует Spring SPeL для присвоения этому свойству этого компонента этого значения. Класс с этим методом является ManagedResource, поэтому я могу получить к нему доступ из JMX.
Затем я определил другой простой класс, присвоил ему свойство и аннотацию компонента. Я также автоматически подключаю этот класс к классу jmx bean, просто чтобы убедиться, что компонент этого типа существует.
Затем я запустил службу SpringBoot.
Затем я вызвал метод из VisualVM.
Сбой, говорящий о том, что не удалось найти компонент с таким именем.
Итак, теперь более подробно.
Вот первый класс:
@Component
@ManagedResource
public class JMXDemonstration {
@Autowired
private ApplicationContext applicationContext;
@Autowired
private SomeRandomThing thing;
@Value("${jmxDemonstration.name}")
private String name;
@ManagedAttribute
public String getName() { return name; }
@ManagedAttribute
public void setName(String name) { this.name = name; }
@ManagedOperation
public String buildHelloWorldMessage() {
return "Hello, " name ": " thing.getId();
}
@ManagedOperation
public void assignValueToBeanProperty(String beanName, String propertyName, String expression) {
Object bean = applicationContext.getBean(beanName);
ExpressionParser parser = new SpelExpressionParser();
SimpleEvaluationContext evalContext = SimpleEvaluationContext.forReadWriteDataBinding().build();
parser.parseExpression(propertyName).setValue(evalContext, bean, expression);
}
}
И вот другой класс:
@Component
public class SomeRandomThing {
private String id;
public String getId() { return id; }
public void setId(String id) { this.id = id; }
}
Когда я вызываю метод из VisualVM, я передаю «SomeRandomThing», «id» и «xxx».
Это приводит к сбою с:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'SomeRandomThing' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:685)
Я также установил точку останова в методе и посмотрел на «this» и подтвердил, что существует допустимое свойство «thing» (если бы его не было, служба не запустилась бы).
Итак, у меня неверный алгоритм имен компонентов по умолчанию? В это трудно поверить, потому что я также провел тест «JMXDemonstration», «name» и «George», и это сработало отлично.
Обновить:
Также обратите внимание, что вызов «ApplicationContext.getBean(SomeRandomThing.class )» возвращает экземпляр компонента этого класса, а также вызов «ApplicationContext.getbeandefinitionname()» возвращает массив, который не содержит «SomeRandomThing», но он содержит «JMXDemonstration».
Почему SomeRandomThing доступен как компонент через автоматическое подключение и через тип, но не через его имя компонента?
Обновить:
О, потому что имя компонента «someRandomThing», а не «SomeRandomThing». Думаю, изначально я ожидал первого, но когда я увидел, что имя компонента для «JMXDemonstration» было «JMXDemonstration», я предположил, что тогда это будет «SomeRandomThing», а не «someRandomThing».
Комментарии:
1. Упоминается ли в документации Spring, что имя компонента автоматически является именем класса? Я могу представить, что оно включает пакет, то есть становится com.project.SomeRandomThing . Я бы проверил внутреннюю работу atComponent или atComponentScan, чтобы найти подробную информацию о том, как Spring создает компоненты.
Ответ №1:
Именование компонента
@Component — это аннотация уровня класса. Во время проверки компонентов Spring Framework автоматически обнаруживает классы, помеченные @Component.
@Component
class CarUtility {
// ...
}
По умолчанию экземпляры bean этого класса имеют то же имя, что и имя класса, с инициалом в нижнем регистре.Кроме того, мы можем указать другое имя, используя необязательный аргумент value этой аннотации.
Конфигурация на основе аннотаций
Для компонента на основе стереотипных аннотаций, если имя явно не указано в поле значения стереотипных аннотаций, то имя снова генерируется с помощью
AnnotationBeanNameGenerator
, которая является реализацией интерфейса стратегии BeanNameGenerator здесь
Если значение аннотации не указывает на имя компонента, соответствующее имя будет создано на основе краткого имени класса (с первой буквой в нижнем регистре). Например:
com.xyz.FooServiceImpl -> fooServiceImpl
При сканировании компонентов в classpath Spring генерирует имена компонентов для неназванных компонентов, следуя правилам, описанным ранее: по сути, берется простое имя класса и преобразуется его начальный символ в нижний регистр. Однако, в (необычном) особом случае, когда имеется более одного символа и оба первого и второго символа являются заглавными, исходный регистр сохраняется. Это те же правила, которые определены в документе java.beans.Introspector.decapitalize (который Spring использует здесь).
Комментарии:
1. Хорошо, тогда можете ли вы объяснить, почему имя компонента для класса JMXDemonstration было JMXDemonstration?
2. Обновлено к вашему вопросу проверьте ссылку на документ, просто скопируйте это содержимое и найдите его. Вы найдете это @DavidM.Karr