Use dropwizards annotation with Spring Boot - java

Instead of measuring by inserting code into each method of interest I intended to use the provided #Timed annotation. But the metrics do not show any corresponding values:
This is my code, the idea is having the execution times of the contained SQL being put into the metrics.
#Component
public class Foo {
private JdbcTemplate jdbcTemplate;
#Autowired
public Metadata(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
#Timed(name = "myapp.get.foo")
public boolean getFoo(final String foo ) {
String foo = jdbcTemplate.query( ...
}
}
The problem with #Timed not showing up is probably because Spring Boot only supports Counter and Gauge.
But #Gauge, #Metered and #Counted don't work either.
What am I missing in order to make at least those metrics annotation work that are supported by Spring Boot ? (1.3.1 in my tests)

You would probably want to take a look at
http://www.ryantenney.com/metrics-spring/
This projects eases integration of dropwizard metrics into Spring Boot projects.
It will automatically create metrics and proxies beans to make the #Timed annotation work.

I ended up not using the annotations and simply implementing MetricSet on beans that I want to instrument. Especially with timers, using one is not that hard.
#Service
public class MyBean implements MetricSet {
Timer putTimer = new Timer();
public void someService() {
try(Context context = putTimer.time()) {
....
}
}
#Override
public Map<String, Metric> getMetrics() {
Map<String,Metric> metrics=new HashMap<>();
metrics.put("mymetricname",putTimer);
return metrics;
}
}
#Slf4j
#Service
public class MetricsContextListener implements ApplicationListener<ContextRefreshedEvent> {
private final MetricRegistry metricRegistry;
public MetricsContextListener(MetricRegistry metricRegistry) {
this.metricRegistry = metricRegistry;
}
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
Map<String, MetricSet> beans = event.getApplicationContext().getBeansOfType(MetricSet.class);
for(Map.Entry<String, MetricSet> e: beans.entrySet()) {
log.info("registering " + e.getKey() + " " + e.getValue().getClass().getName());
metricRegistry.register(e.getKey(), e.getValue());
}
}
}
Also you'll probably want to create your own MetricRegistry. We had some issues with spring boot creating one but our spring tests failing because it was missing. If you create one yourself, that problem goes away. Simply add this to one of your #Configuration classes
#Bean
public MetricRegistry metricRegistry() {
// explicitly register a metricRegistry so we can run our spring tests without relying on spring boot creating
// one for us. Spring boot seems to do the right thing either way.
// Used to register codahale metrics from MetricSet implementing beans.
return new MetricRegistry();
}
With all this in place, Spring boot does the right thing and adds the metrics to /metrics.

Related

How do I create multiple Spring beans of the same type without defining each one

I've seen a lot of workaround-looking things regarding what I'm trying to do using BeanDefinitionRegistryPostProcessor, but I wondered if there was a way to tap directly into Spring's bean creation API to override some behavior.
What I would like to see is something like this (note the 's' in #Components):
#Components(prefix="myBean-", numberOfInstances="${myapp.mybean.numberOfInstances}")
public class MyBean {
private final MyService myService;
public MyBean(final MyService myService) {
this.myService = myService;
}
#Scheduled(fixedDelayString = "${myapp.mybean.fixedDelay}")
public myJob() {
System.out.println("I'm working!");
}
}
I am basically looking for the same functionality of #Component where I can specify how many instances to make and just have the name generated.
As I mentioned before, the only way I have found to do this sort of thing (specifically for scheduled tasks now) is to use the BeanDefinitionRegistryPostProcessor to create the instances or create a custom SchedulingConfigurer to configure the tasks manually without using Spring beans, which means all the Runnable's dependencies have to be wired into the SchedulingConfigurer, and that just feels dirty.
Is this even possible--to add a new annotation to scan for and invoke some other way to create the beans?
Update
Thanks to #vince for helping me realize I don't need a separete bean for each job; I just have to configure the singleton multiple times into the FixedDelayTask.
#Component
public class MyBean {
private final MyService myService;
public MyBean(final MyService myService) {
this.myService = myService;
}
// Remove #Scheduled here since we have to configure multiple
// instances manually. This is where it would be nice to specify
// how many jobs of the same type you want.
// #Scheduled(fixedDelayString = "${myapp.mybean.fixedDelay}")
public myJob() {
System.out.println("I'm working!");
}
}
#Configuration
#EnableScheduling
public class MyBeanTaskConfiguration implements SchedulingConfigurer {
private final MyBean myBean;
public MyBeanTaskConfiguration(MyBean myBean) {
this.myBean = myBean;
}
#Override
public void configureTasks(final ScheduledTaskRegistrar taskRegistrar) {
for (int i = 0; i < numberOfWorkers; i++) {
taskRegistrar.scheduleFixedDelayTask(
new FixedDelayTask(
myBean,
repeatIntervalMs,
repeatIntervalMs / numberOfWorkers * i + startDelayMs
)
);
}
}
}
Actually I'm wondering why u wanna do this. According to the IOC philosophy, beans should be delegated to container and clients don't need to care about beans' lifecycles. That's why Spring provides #Scope to support different bean scopes like singleton/request/session. So I don't think it a good way to control the specific number of a certain bean, besides, beans should theoretically be non-stateful, thus a single instance is fairly enough.
Prototype scoped beans will be provided as a new instance for each request to the container.
#Component
#Scope("prototype")
public class MyBean {
private final MyService myService;
public MyBean(final MyService myService) {
this.myService = myService;
}
// ...
}
// Get two separate instances
MyBean bean1 = (MyBean)applicationContext.getBean("myBean");
MyBean bean2 = (MyBean)applicationContext.getBean("myBean");

Returning Singleton beans depending on input in Spring

Let's say I have the following:
#Component
#NoArgsConstructor
public class ToolFactory {
public Tool getTool(String type) {
return StaticToolProvider.getTool(type);
}
}
This class will be injected elsewhere and called like this:
Tool screwdriver = ToolFactory.getTool("screwdriver")
If the tools can be screwdriver, hammer, or wrench, I want Spring to create Singleton beans for each, and return them when getTool() is called. I believe #Provides #Singleton would do this in Guice, but how could I do it here?
I would create map with all needed beans. Map will be singleton by default and unmodifiable to prevent anyone changing it by mistake. If you need hammer to be spring bean just autowire it, if no you can just use regular object creation using new
#Configuration
class Config {
#Bean
Map<String, Tool> tools(Hammer hammer) {
Map<String, Tool> map = new HashMap<>();
map.put("hammer", hammer);
//map.put("hammer",new Hammer())
return Collections.unmodifiableMap(map);
}
}
#Component
public class Container {
private Map<String, Tool> tools;
#Autowired
public Container(Map<String, Tool> tools) {
this.tools = tools;
}
Tool getTool(String tool) {
return tools.get(tool);
}
}

How to control loading order when mixing auto-configure and component scan in Spring Boot

The user story is like this:
We have exposed some APIs through library jars which use the Spring Boot auto-configure mechanism. The APIs need some glue logic during initialization, so we put them under #PostConstruct block of some #Configurations and register them as auto-configured.
The user code is based on #SpringBootApplication, while they prefer to use #ComponentScan to define beans instead auto-configure.
So the issue comes, Spring always tries to load the beans defined by #ComponentScan first, then those auto-configured beans. So if any user bean relies on the API that not been initialized, it sure will fail.
It seems there's no way to define the bean order when mixing the auto-configured and component-scanned beans. The #Order, #AutoConfigureOrder, #AutoConfigureAfter, #AutoConfigureBefore annotation and Ordered interface only work among all auto configured beans.
Of course if user uses auto-configure for their beans too, it will work without problem. But from user's perspective, #ComponentScan looks a more natural and easier way, especially #SpringBootApplication implies the #ComponentScan of current java package.
Our current workaround is to eager load those API initialization configures at a very-early stage. For web context, it's ServletContextInitializer.onStartup(), and for other generic context, it's LoadTimeWeaverAware's #PostConstruct.
#Configuration
#ConditionalOnWebApplication
#AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
public class EagerInitWebContextInitializer implements ServletContextInitializer, PriorityOrdered
{
#Autowired
private ApplicationContext appContext;
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
String[] beanNames = appContext.getBeanNamesForAnnotation(EagerInitializer.class);
if (beanNames != null) {
// pre-load all eager initializers
for (String name : beanNames) {
appContext.getBean(name);
}
}
}
#Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
}
#Configuration
#ConditionalOnNotWebApplication
#AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
public class EagerInitGenericContextInitializer implements LoadTimeWeaverAware, PriorityOrdered
{
#Autowired
private ApplicationContext appContext;
#PostConstruct
protected void init() {
String[] beanNames = appContext.getBeanNamesForAnnotation(EagerInitializer.class);
if (beanNames != null) {
// pre-load all eager initializers
for (String name : beanNames) {
appContext.getBean(name);
}
}
}
#Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
#Override
public void setLoadTimeWeaver(LoadTimeWeaver loadTimeWeaver) {
// does nothing
}
}
This actually works well. But just wondering is there any better way to achieve this or whether future Spring version can provide a similar systematic way?

Loading Beans based on hostname

I am writing services in Spring boot that get their configurations from Spring cloud. These services are multi-tenant and the tenant is based on the host name.
what I have now is
public class MyController {
#Autowired
public MyController(MyServiceFactory factory) {
...
}
#RequestMapping("some/path/{id}")
ResponseEntity<SomeEntity> getSomeEntity(#RequestHeader header, #PathVariable id) {
return factory.getMyService(header).handle(id);
}
}
where MyServiceFactory looks something like...
public class MyServiceFactory {
private final HashMap<String, MyService> serviceRegistry = new HashMap<>();
public MyService getMyService(String key) {
return serviceRegistry.get(key);
}
MyServiceFactory withService(String key, MyService service) {
this.serviceRegistry.put(key, service);
return this;
}
}
then in a configuration file
#Configuration
public ServiceFactoryConfiguration {
#Bean
public MyServiceFactory getMyServiceFactory() {
return new MyServiceFactory()
.withService("client1", new MyService1())
.withService("client2", new MyService2());
}
}
While what I have now works, I don't like that I need to create a factory for every dependency my controller may have. I'd like to have my code look something like this...
public class MyController {
#Autowired
public MyController(MyService service) {
...
}
#RequestMapping("some/path/{id}")
ResponseEntity<SomeEntity> getSomeEntity(#PathVariable id) {
return service.handle(id);
}
}
with a configuration file like
#Configuration
public class MyServiceConfiguration() {
#Bean
#Qualifier("Client1")
public MyService getMyService1() {
return new MyService1();
}
#Bean
#Qualifier("Client2")
public MyService getMyService2() {
return new MyService2();
}
}
I can get the code that I want to write if I use a profile at application start up. But I want to have lots of different DNS records pointing to the same (pool of) instance(s) and have an instance be able to handle requests for different clients. I want to be able to swap out profiles on a per request basis.
Is this possible to do?
Spring profiles would not help here, you would need one application context per client, and that seems not what you want.
Instead you could use scoped beans.
Create your client dependent beans with scope 'client' :
#Bean
#Scope(value="client",proxyMode = ScopedProxyMode.INTERFACES)
#Primary
MyService myService(){
//does not really matter, which instance you create here
//the scope will create the real instance
//may be you can even return null, did not try that.
return new MyServiceDummy();
}
There will be at least 3 beans of type MyService : the scoped one, and one for each client. The annotation #Primary tells spring to always use the scoped bean for injection.
Create a scope :
public class ClientScope implements Scope {
#Autowired
BeanFactory beanFactory;
Object get(String name, ObjectFactory<?> objectFactory){
//we do not use the objectFactory here, instead the beanFactory
//you somehow have to know which client is the current
//from the config, current request, session, or ThreadLocal..
String client=findCurrentClient(..);
//client now is something like 'Client1'
//check if your cache (HashMap) contains an instance with
//BeanName = name for the client, if true, return that
..
//if not, create a new instance of the bean with the given name
//for the current client. Easiest way using a naming convention
String clientBeanName=client+'.'+name;
Object clientBean=BeanFactory.getBean(clientBeanName);
//put in cache ...
return clientBean;
};
}
And your client specific beans are configured like this :
#Bean('Client1.myService')
public MyService getMyService1() {
return new MyService1();
}
#Bean('Client2.myService')
public MyService getMyService2() {
return new MyService2();
}
Did not test it but used it in my projects. Should work.
tutorial spring custom scope

How to instantiate Spring managed beans at runtime?

I stuck with a simple refactoring from plain Java to Spring. Application has a "Container" object which instantiates its parts at runtime. Let me explain with the code:
public class Container {
private List<RuntimeBean> runtimeBeans = new ArrayList<RuntimeBean>();
public void load() {
// repeated several times depending on external data/environment
RuntimeBean beanRuntime = createRuntimeBean();
runtimeBeans.add(beanRuntime);
}
public RuntimeBean createRuntimeBean() {
// should create bean which internally can have some
// spring annotations or in other words
// should be managed by spring
}
}
Basically, during load container asks some external system to provide him information about number and configuration of each RuntimeBean and then it create beans according to given spec.
The problem is: usually when we do in Spring
ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfiguration.class);
Container container = (Container) context.getBean("container");
our object is fully configured and have all dependencies injected. But in my case I have to instantiate some objects which also needs dependency injection after I execute load() method.
How can I achieve that?
I am using a Java-based config. I already tried making a factory for RuntimeBeans:
public class BeanRuntimeFactory {
#Bean
public RuntimeBean createRuntimeBean() {
return new RuntimeBean();
}
}
Expecting #Bean to work in so called 'lite' mode. http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/Bean.html Unfortunately, I found no difference with simply doing new RuntimeBean();
Here is a post with a similar issue: How to get beans created by FactoryBean spring managed?
There is also http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/beans/factory/annotation/Configurable.html but it looks like a hammer in my case.
I also tried ApplicationContext.getBean("runtimeBean", args) where runtimeBean has a "Prototype" scope, but getBean is an awful solution.
Update 1
To be more concrete I am trying to refactor this class:
https://github.com/apache/lucene-solr/blob/trunk/solr/core/src/java/org/apache/solr/core/CoreContainer.java
#see #load() method and find "return create(cd, false);"
Update 2
I found quite interesting thing called "lookup method injection" in spring documentation:
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-factory-lookup-method-injection
And also an interesting jira ticket https://jira.spring.io/browse/SPR-5192 where Phil Webb says https://jira.spring.io/browse/SPR-5192?focusedCommentId=86051&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-86051 that javax.inject.Provider should be used here (it reminds me Guice).
Update 3
There is also http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/beans/factory/config/ServiceLocatorFactoryBean.html
Update 4
The issue with all these 'lookup' methods is they don't support passing any arguments.. I also need to pass arguments as I would do with applicationContext.getBean("runtimeBean", arg1, arg2). Looks like it was fixed at some point with https://jira.spring.io/browse/SPR-7431
Update 5
Google Guice have a neat feature for it called AssistedInject. https://github.com/google/guice/wiki/AssistedInject
Looks like I found a solution. As I am using java based configuration it is even simpler than you can imagine. Alternative way in xml would be lookup-method, however only from spring version 4.1.X as it supports passing arguments to the method.
Here is a complete working example:
public class Container {
private List<RuntimeBean> runtimeBeans = new ArrayList<RuntimeBean>();
private RuntimeBeanFactory runtimeBeanFactory;
public void load() {
// repeated several times depending on external data/environment
runtimeBeans.add(createRuntimeBean("Some external info1"));
runtimeBeans.add(createRuntimeBean("Some external info2"));
}
public RuntimeBean createRuntimeBean(String info) {
// should create bean which internally can have some
// spring annotations or in other words
// should be managed by spring
return runtimeBeanFactory.createRuntimeBean(info);
}
public void setRuntimeBeanFactory(RuntimeBeanFactory runtimeBeanFactory) {
this.runtimeBeanFactory = runtimeBeanFactory;
}
}
public interface RuntimeBeanFactory {
RuntimeBean createRuntimeBean(String info);
}
//and finally
#Configuration
public class ApplicationConfiguration {
#Bean
Container container() {
Container container = new Container(beanToInject());
container.setBeanRuntimeFactory(runtimeBeanFactory());
return container;
}
// LOOK HOW IT IS SIMPLE IN THE JAVA CONFIGURATION
#Bean
public BeanRuntimeFactory runtimeBeanFactory() {
return new BeanRuntimeFactory() {
public RuntimeBean createRuntimeBean(String beanName) {
return runtimeBean(beanName);
}
};
}
#Bean
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
RuntimeBean runtimeBean(String beanName) {
return new RuntimeBean(beanName);
}
}
class RuntimeBean {
#Autowired
Container container;
}
That's it.
Thanks everyone.
i think that your concept is wrong by using
RuntimeBean beanRuntime = createRuntimeBean();
you are bypassing Spring container and resorting to using regular java constructor therefore any annotations on factory method are ignored and this bean is never managed by Spring
here is the solution to create multiple prototype beans in one method, not pretty looking but should work, I autowired container in RuntimeBean as proof of autowiring shown in log also you can see in log that every bean is new instance of prototype when you run this .
'
#Configuration
#ComponentScan
#EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
ApplicationContext context = new AnnotationConfigApplicationContext(Application.class);
Container container = (Container) context.getBean("container");
container.load();
}
}
#Component
class Container {
private List<RuntimeBean> runtimeBeans = new ArrayList<RuntimeBean>();
#Autowired
ApplicationContext context;
#Autowired
private ObjectFactory<RuntimeBean> myBeanFactory;
public void load() {
// repeated several times depending on external data/environment
for (int i = 0; i < 10; i++) {
// **************************************
// COMENTED OUT THE WRONG STUFFF
// RuntimeBean beanRuntime = context.getBean(RuntimeBean.class);
// createRuntimeBean();
//
// **************************************
RuntimeBean beanRuntime = myBeanFactory.getObject();
runtimeBeans.add(beanRuntime);
System.out.println(beanRuntime + " " + beanRuntime.container);
}
}
#Bean
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public RuntimeBean createRuntimeBean() {
return new RuntimeBean();
}
}
// #Component
class RuntimeBean {
#Autowired
Container container;
} '
A simple approach:
#Component
public class RuntimeBeanBuilder {
#Autowired
private ApplicationContext applicationContext;
public MyObject load(String beanName, MyObject myObject) {
ConfigurableApplicationContext configContext = (ConfigurableApplicationContext) applicationContext;
SingletonBeanRegistry beanRegistry = configContext.getBeanFactory();
if (beanRegistry.containsSingleton(beanName)) {
return beanRegistry.getSingleton(beanName);
} else {
beanRegistry.registerSingleton(beanName, myObject);
return beanRegistry.getSingleton(beanName);
}
}
}
#Service
public MyService{
//inject your builder and create or load beans
#Autowired
private RuntimeBeanBuilder builder;
//do something
}
Instead of using SingletonBeanRegistry you can use this:
BeanFactory beanFactory = configContext.getBeanFactory();
Anyway SingletonBeanBuilder extends HierarchicalBeanFactory and HierarchicalBeanFactory extends BeanFactory
You don't need the Container because all of the runtime objects should be created, held and managed by ApplicationContext. Think about a web application, they are much the same. Each request contains external data/environment info as you mentioned above. What you need is a prototype/request scoped bean like ExternalData or EnvironmentInfo which can read and hold runtime data through a static way, let's say a static factory method.
<bean id="externalData" class="ExternalData"
factory-method="read" scope="prototype"></bean>
<bean id="environmentInfo" class="EnvironmentInfo"
factory-method="read" scope="prototype/singleton"></bean>
<bean class="RuntimeBean" scope="prototype">
<property name="externalData" ref="externalData">
<property name="environmentInfo" ref="environmentInfo">
</bean>
If you do need a container to save the runtime objects, code should be
class Container {
List list;
ApplicationContext context;//injected by spring if Container is not a prototype bean
public void load() {// no loop inside, each time call load() will load a runtime object
RuntimeBean bean = context.getBean(RuntimeBean.class); // see official doc
list.add(bean);// do whatever
}
}
Official doc Singleton beans with prototype-bean dependencies.
It is possible to register beans dynamically by using BeanFactoryPostProcesor. Here you can do that while the application is booting (spring's application context has been initialized). You can not register beans latest, but on the other hand, you can make use of dependency injection for your beans, as they become "true" Spring beans.
public class DynamicBeansRegistar implements BeanFactoryPostProcessor {
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
if (! (beanFactory instanceof BeanDefinitionRegistry)) {
throw new RuntimeException("BeanFactory is not instance of BeanDefinitionRegistry");
}
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
// here you can fire your logic to get definition for your beans at runtime and
// then register all beans you need (possibly inside a loop)
BeanDefinition dynamicBean = BeanDefinitionBuilder.
.rootBeanDefinition(TheClassOfYourDynamicBean.class) // here you define the class
.setScope(BeanDefinition.SCOPE_SINGLETON)
.addDependsOn("someOtherBean") // make sure all other needed beans are initialized
// you can set factory method, constructor args using other methods of this builder
.getBeanDefinition();
registry.registerBeanDefinition("your.bean.name", dynamicBean);
}
#Component
class SomeOtherClass {
// NOTE: it is possible to autowire the bean
#Autowired
private TheClassOfYourDynamicBean myDynamicBean;
}
As presented above, you can still utilize Spring's Dependency Injection, because the post processor works on the actual Application Context.

Categories

Resources