3

I try do a fill repository with metrics in spring boot, but I have the problem that when I execute I recive error.

This is my error:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'actuatorMetricsPrinter' defined in file [ActuatorMetricsPrinter.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [java.util.Collection]: : No qualifying bean of type [org.springframework.boot.actuate.endpoint.PublicMetrics] found for dependency [collection of org.springframework.boot.actuate.endpoint.PublicMetrics]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.boot.actuate.endpoint.PublicMetrics] found for dependency [collection of org.springframework.boot.actuate.endpoint.PublicMetrics]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:747)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:185)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1115)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1018)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:706)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:762)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:109)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:691)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:952)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:941)
at hello.Application.main(Application.java:14)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.boot.actuate.endpoint.PublicMetrics] found for dependency [collection of org.springframework.boot.actuate.endpoint.PublicMetrics]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1118)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:919)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:862)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:811)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:739)
... 18 common frames omitted

And this is my code when I recive error:

    @Autowired
public DummyController(ActuatorMetricsPrinter metricsPrinter) {
    this.metricsPrinter = metricsPrinter;
}

I have a class ActuatorMetricsPrinter that show the metrics but I have a problem when try fill this repository

*EDIT *

@Component
public class ActuatorMetricsPrinter {
private MetricRepository repository;

private static final String TEMPLATE = "Metric: %s [%s]";
private Collection<PublicMetrics> publicMetrics = null;

public String printAllMetrics() {

    StringBuilder sb = new StringBuilder();

    for (PublicMetrics pm : publicMetrics) {
        sb.append("Public Metric: " + pm.getClass().getName());
        sb.append("\n\n");

        for (Metric<?> m : pm.metrics()) {
            sb.append(String.format(TEMPLATE, m.getName(), m.getValue().toString()));
            sb.append("\n");
        }
    }

    return sb.toString();
}

@Autowired
public void MetricExporterService(MetricRepository repository) {
    this.repository = repository;
}

And

@Controller
public class DummyController {

private final ActuatorMetricsPrinter metricsPrinter;

@Autowired
public DummyController(ActuatorMetricsPrinter metricsPrinter) {
    this.metricsPrinter = metricsPrinter;
}

@RequestMapping(value = "/customMetrics", method = RequestMethod.GET)
@ResponseBody
public String printMetrics() {
    return metricsPrinter.printAllMetrics();
}

@Bean
public ActuatorMetricsPrinter publicMetrics() {
    return new ActuatorMetricsPrinter();
}

}

Thank you very much!

herzo
  • 105
  • 4
  • 12

2 Answers2

2

Spring beans factory not found a bean Collection<PublicMetrics> publicMetrics for autowarid; try to create a list of PublicMetrics
see :
Spring autowire a list
Auto-wiring a List using util schema gives NoSuchBeanDefinitionException

Community
  • 1
  • 1
Naami
  • 349
  • 3
  • 9
0

In your case the actual problem is initializing the constructor for ActuatorMetricsPrinter. You have it Autowired to take in a Collection so Spring is trying to find the set of PublicMetrics beans to use as a collection and it cannot find any. Here is the error in what you provided above that points to that. I ran into the same issue myself at one point.

No qualifying bean of type [org.springframework.boot.actuate.endpoint.PublicMetrics] found for dependency [collection of org.springframework.boot.actuate.endpoint.PublicMetrics]: expected at least 1 bean which qualifies as autowire candidate for this dependency.

From the Spring Docs on Autowired:

In case of a Collection or Map dependency type, the container will autowire all beans matching the declared value type. In case of a Map, the keys must be declared as type String and will be resolved to the corresponding bean names.

Since the PublicMetrics are not declared as beans I think the right way to do it is by autowiring to a MetricRepository. See this link and the Exporting Metrics section there as a reference. There is a link to a sample application. Here is some modified code that you can use.

@Autowired
public MetricExporterService(MetricRepository repository) {
    this.repository = repository;
}

public String printAllMetrics() {

    StringBuilder sb = new StringBuilder();

    for (Metric metric : repository.findAll()) {
        sb.append(String.format(TEMPLATE, metric.getName(), metric.getValue().toString()));
    }

    return sb.toString();
}
Rob Baily
  • 2,770
  • 17
  • 26
  • I dont undestand. I need add this bean. But new element create PublicMetrics() that is this?? – herzo May 03 '15 at 12:19
  • Mine was just a simple test without all of the actual classes you would use. Yes I believe you would need to create beans for any of the PublicMetrics objects that you want to be included in your collection as being AutoWired in your construction. I am not entirely sure if this is possible as the Spring Boot Actuator may not expose these as beans. – Rob Baily May 04 '15 at 12:50
  • In looking at it a bit more I think the right way to do it is by autowiring to a MetricRepository. See http://kielczewski.eu/2015/01/application-metrics-with-spring-boot-actuator/ as a reference with a sample application. Let me know if that works for you. – Rob Baily May 04 '15 at 12:53
  • I updated the answer to reflect some info above. I have tried it myself and I get any metrics to do with services I have created but I don't get things like the container (Tomcat) or JVM metrics. Are those the ones you were looking to export? – Rob Baily May 04 '15 at 13:59
  • I get that run with your help. Thank you very much!. But I have a problem, because I want show system metrics that I obtained with actuator /metrics but if I change this code by publicMetrics type equals I put I recive java null pointer. What is the problem?? I edit the code – herzo May 04 '15 at 20:35
  • Hmm, I am not sure about your null pointer problem as I don't quite understand. Please post some code if you can. In terms of the system metrics I have looked but don't see how they show up anywhere. In the Spring Boot doc they mention that if you have Spring Messaging in your classpath that a MessageChannel is created for any event updates. I have not tried it but you can and see if that gets you the updates you want. I will need to look some more to try and what is happening under the covers. – Rob Baily May 05 '15 at 13:02
  • I see either that you don't have the constructor named right in ActuatorMetricsPrinter (you have MetricExporterService) or you are still using the public metrics. Check out my fork of a Spring Actuator guide at https://github.com/rob-baily/gs-actuator-service and review that for what I did. I also just tried autowiring a Collection attribute and that worked as well. Check out what I have at GitHub and see where yours might be different. You might have some other configuration issue. – Rob Baily May 06 '15 at 11:25
  • Thank you very much for you time. I prove your solution and go very good. Later I adapted for web services and I managed to make it work well. I have a doubt, because I need the anottation Service in the class?, if I delete this I recive error, but it isn´t a service because I delete scheduled and only excute when I call web services – herzo May 10 '15 at 19:28
  • Glad it worked for you. You will either need to annotate your class with the [Service](http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/stereotype/Service.html) annotation or set up a Bean definition for Autowiring to work. The Service annotation allows the bean definition to be done via automatic class scanning. I pushed a commit for an example of how it would work as a Bean definition to the GitHub link above. There are multiple ways to define beans but in your can I think using the Service annotation would probably make the most sense. – Rob Baily May 11 '15 at 13:54