Spring Boot - Getting the hostname in application.properties for Spring-Kafka client Id - spring-boot

I am working on a project with Spring-Kafka and Boot and am wanting to get the hostname in the application.properties for the property spring.kafka.consumer.client-Id so that each of my consumers can be distinguished in the server side logs should there be an issue.
Is there a way i could do that? I check on the spring boot reference guide and java.lang.System class but could not find fruitful pointers.

Here's one way - add an EnvironmentAware bean to your config...
#SpringBootApplication
public class So43191948Application implements EnvironmentAware {
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext context = SpringApplication.run(So43191948Application.class, args);
#SuppressWarnings("unchecked")
KafkaTemplate<String, String> template = context.getBean(KafkaTemplate.class);
template.send("so43191948", "foo");
Thread.sleep(10000);
context.close();
}
#KafkaListener(topics = "so43191948")
public void foo(String in) {
System.out.println(in);
}
#Override
public void setEnvironment(Environment environment) {
Properties props = new Properties();
try {
props.setProperty("spring.kafka.consumer.client-id", InetAddress.getLocalHost().getHostName() + ".client");
PropertiesPropertySource propertySource = new PropertiesPropertySource("myProps", props);
if (environment instanceof StandardEnvironment) {
((StandardEnvironment) environment).getPropertySources().addFirst(propertySource);
}
}
catch (UnknownHostException e) {
e.printStackTrace();
}
}
}
In this case, I did it in the boot app itself but it can be done in any bean.
2017-04-03 16:12:32.646 INFO 64879 --- [ main] o.a.k.clients.consumer.ConsumerConfig
: ConsumerConfig values:
auto.commit.interval.ms = 5000
auto.offset.reset = earliest
bootstrap.servers = [localhost:9092]
check.crcs = true
client.id = myhost.client
...
application.properties:
spring.kafka.consumer.client-id=foo
spring.kafka.consumer.group-id=myGroup
spring.kafka.consumer.auto-offset-reset=earliest
As you can see, the client-id is overridden.

import java.net.InetAddress;
import java.net.UnknownHostException;
private String getHostAddress() {
String hostaddress = "";
try {
hostaddress = InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
log.error("Error while fetching hostaddress:", e);
}
return hostaddress;}

Related

Spring Boot Kafka Configure DefaultErrorHandler?

I created a batch-consumer following the Spring Kafka docs:
#SpringBootApplication
public class ApplicationConsumer {
private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationConsumer.class);
private static final String TOPIC = "foo";
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(ApplicationConsumer.class, args);
}
#Bean
public RecordMessageConverter converter() {
return new JsonMessageConverter();
}
#Bean
public BatchMessagingMessageConverter batchConverter() {
return new BatchMessagingMessageConverter(converter());
}
#KafkaListener(topics = TOPIC)
public void listen(List<Name> ps) {
LOGGER.info("received name beans: {}", Arrays.toString(ps.toArray()));
}
}
I was able to successfully get the consumer running by defining the following additional configuration env variables, that Spring automatically picks up:
export SPRING_KAFKA_BOOTSTRAP-SERVERS=...
export SPRING_KAFKA_CONSUMER_GROUP-ID=...
So the above code works. But now I want to customize the default error handler to use exponential backoff. From the ref docs I tried adding the following to ApplicationConsumer class:
#Bean
public ConcurrentKafkaListenerContainerFactory<?, ?> kafkaListenerContainerFactory() {
ConcurrentKafkaListenerContainerFactory<String, Object> factory = new ConcurrentKafkaListenerContainerFactory<>();
factory.setCommonErrorHandler(new DefaultErrorHandler(new ExponentialBackOffWithMaxRetries(10)));
factory.setConsumerFactory(consumerFactory());
return factory;
}
#Bean
public ConsumerFactory<String, Object> consumerFactory() {
return new DefaultKafkaConsumerFactory<>(consumerConfigs());
}
#Bean
public Map<String, Object> consumerConfigs() {
Map<String, Object> props = new HashMap<>();
return props;
}
But now I get errors saying that it can't find some of the configuration. It looks like I'm stuck having to redefine all of the properties in consumerConfigs() that were already being automatically defined before. This includes everything from bootstrap server uris to the json-deserialization config.
Is there a good way to update my first version of the code to just override the default-error handler?
Just define the error handler as a #Bean and Boot will automatically wire it into its auto configured container factory.
EDIT
This works as expected for me:
#SpringBootApplication
public class So70884203Application {
public static void main(String[] args) {
SpringApplication.run(So70884203Application.class, args);
}
#Bean
DefaultErrorHandler eh() {
return new DefaultErrorHandler((rec, ex) -> {
System.out.println("Recovered: " + rec);
}, new FixedBackOff(0L, 0L));
}
#KafkaListener(id = "so70884203", topics = "so70884203")
void listen(String in) {
System.out.println(in);
throw new RuntimeException("test");
}
#Bean
NewTopic topic() {
return TopicBuilder.name("so70884203").partitions(1).replicas(1).build();
}
}
foo
Recovered: ConsumerRecord(topic = so70884203, partition = 0, leaderEpoch = 0, offset = 0, CreateTime = 1643316625291, serialized key size = -1, serialized value size = 3, headers = RecordHeaders(headers = [], isReadOnly = false), key = null, value = foo)

Loading a custom ApplicationContextInitializer in AWS Lambda Spring boot

How to loada custom ApplicationContextInitializer to in spring boot AWS Lambda?
I have an aws lambda application using spring boot, I would like to write an ApplicationContextInitializer for decrypting database passwords. I have the following code that works while running it as a spring boot application locally, but when I deploy it to the AWS console as a lambda it doesn't work.
Here is my code
1. applications.properties
spring.datasource.url=url
spring.datasource.username=testuser
CIPHER.spring.datasource.password=encryptedpassword
The following code is the ApplicationContextInitializer, assuming password is Base64 encoded for testing only (In the actual case it will be encrypted by AWM KMS). The idea here is if the key is starting with 'CIPHER.' (as in CIPHER.spring.datasource.password)I assume it's value needs to be decrypted and another key value pair with actual, key (here spring.datasource.password) and its decrypted value will be added at context initialization.
will be like spring.datasource.password=decrypted password
#Component
public class DecryptedPropertyContextInitializer
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
private static final String CIPHER = "CIPHER.";
#Override
public void initialize(ConfigurableApplicationContext applicationContext) {
ConfigurableEnvironment environment = applicationContext.getEnvironment();
for (PropertySource<?> propertySource : environment.getPropertySources()) {
Map<String, Object> propertyOverrides = new LinkedHashMap<>();
decodePasswords(propertySource, propertyOverrides);
if (!propertyOverrides.isEmpty()) {
PropertySource<?> decodedProperties = new MapPropertySource("decoded "+ propertySource.getName(), propertyOverrides);
environment.getPropertySources().addBefore(propertySource.getName(), decodedProperties);
}
}
}
private void decodePasswords(PropertySource<?> source, Map<String, Object> propertyOverrides) {
if (source instanceof EnumerablePropertySource) {
EnumerablePropertySource<?> enumerablePropertySource = (EnumerablePropertySource<?>) source;
for (String key : enumerablePropertySource.getPropertyNames()) {
Object rawValue = source.getProperty(key);
if (rawValue instanceof String && key.startsWith(CIPHER)) {
String cipherRemovedKey = key.substring(CIPHER.length());
String decodedValue = decode((String) rawValue);
propertyOverrides.put(cipherRemovedKey, decodedValue);
}
}
}
}
public String decode(String encodedString) {
byte[] valueDecoded = org.apache.commons.codec.binary.Base64.decodeBase64(encodedString);
return new String(valueDecoded);
}
Here is the Spring boot initializer
#SpringBootApplication
#ComponentScan(basePackages = "com.amazonaws.serverless.sample.springboot.controller")
public class Application extends SpringBootServletInitializer {
#Bean
public HandlerMapping handlerMapping() {
return new RequestMappingHandlerMapping();
}
#Bean
public HandlerAdapter handlerAdapter() {
return new RequestMappingHandlerAdapter();
}
#Bean
public HandlerExceptionResolver handlerExceptionResolver() {
return new HandlerExceptionResolver() {
#Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
return null;
}
};
}
//loading the initializer here
public static void main(String[] args) {
SpringApplication application=new SpringApplication(Application.class);
application.addInitializers(new DecryptedPropertyContextInitializer());
application.run(args);
}
This is working when run as a spring boot appliaction, But when it deployed as a lambda into AWS the main() method in my SpringBootServletInitializer will never be called by lambda. Here is my Lambda handler.
public class StreamLambdaHandler implements RequestStreamHandler {
private static Logger LOGGER = LoggerFactory.getLogger(StreamLambdaHandler.class);
private static SpringBootLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler;
static {
try {
handler = SpringBootLambdaContainerHandler.getAwsProxyHandler(Application.class);
handler.onStartup(servletContext -> {
FilterRegistration.Dynamic registration = servletContext.addFilter("CognitoIdentityFilter", CognitoIdentityFilter.class);
registration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");
});
} catch (ContainerInitializationException e) {
e.printStackTrace();
throw new RuntimeException("Could not initialize Spring Boot application", e);
}
}
#Override
public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context)
throws IOException {
handler.proxyStream(inputStream, outputStream, context);
outputStream.close();
}
}
What change is to be made in the code to load the ApplicationContextInitializer by Lambda? Any help will be highly appreciated.
I was able to nail it in the following way.
First changed the property value with place holder with a prefix, where the prefix denotes the values need to be decrypted, ex.
spring.datasource.password=${MY_PREFIX_placeHolder}
aws lambda environment variable name should match to the placeholder
('MY_PREFIX_placeHolder') and it value is encrypted using AWS KMS (This sample is base64 decoding).
create an ApplicationContextInitializer which will decrypt the property value
public class DecryptedPropertyContextInitializer
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
private static final String CIPHER = "MY_PREFIX_";
#Override
public void initialize(ConfigurableApplicationContext applicationContext) {
ConfigurableEnvironment environment = applicationContext.getEnvironment();
for (PropertySource<?> propertySource : environment.getPropertySources()) {
Map<String, Object> propertyOverrides = new LinkedHashMap<>();
decodePasswords(propertySource, propertyOverrides);
if (!propertyOverrides.isEmpty()) {
PropertySource<?> decodedProperties = new MapPropertySource("decoded "+ propertySource.getName(), propertyOverrides);
environment.getPropertySources().addBefore(propertySource.getName(), decodedProperties);
}
}
}
private void decodePasswords(PropertySource<?> source, Map<String, Object> propertyOverrides) {
if (source instanceof EnumerablePropertySource) {
EnumerablePropertySource<?> enumerablePropertySource = (EnumerablePropertySource<?>) source;
for (String key : enumerablePropertySource.getPropertyNames()) {
Object rawValue = source.getProperty(key);
if (rawValue instanceof String && key.startsWith(CIPHER)) {
String decodedValue = decode((String) rawValue);
propertyOverrides.put(key, decodedValue);
}
}
}
}
public String decode(String encodedString) {
byte[] valueDecoded = org.apache.commons.codec.binary.Base64.decodeBase64(encodedString);
return new String(valueDecoded);
}
}
The above code will decrypt all the values with prefix MY_PREFIX_ and add them at the top of the property source.
As the spring boot is deployed into aws lambda, lambda will not invoke the main() function, so if the ApplicationContextInitializer is initialized in main() it is not going to work. In order to make it work need to override createSpringApplicationBuilder() method of SpringBootServletInitializer, so SpringBootServletInitializer will be like
#SpringBootApplication
#ComponentScan(basePackages = "com.amazonaws.serverless.sample.springboot.controller")
public class Application extends SpringBootServletInitializer {
#Bean
public HandlerMapping handlerMapping() {
return new RequestMappingHandlerMapping();
}
#Bean
public HandlerAdapter handlerAdapter() {
return new RequestMappingHandlerAdapter();
}
#Bean
public HandlerExceptionResolver handlerExceptionResolver() {
return new HandlerExceptionResolver() {
#Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
return null;
}
};
}
#Override
protected SpringApplicationBuilder createSpringApplicationBuilder() {
SpringApplicationBuilder builder = new SpringApplicationBuilder();
builder.initializers(new DecryptedPropertyContextInitializer());
return builder;
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
No need to make any changes for the lambdahandler.

How and where to invoke HeaderValueRouter and HeaderEnricher for jms or activemq with spring-integration

In my project ,we use spring-integration to implement the queue. The configuration for Header-Value-Router is in the xml as below:
<header-value-router input-channel="jmsUVMasterMessageChannel"
header-name="METADATA_TYPE" default-output-channel="nullChannel"
resolution-required="false">
<mapping value="ASSEMBLY" channel="downloadImageToS3Channel" />
<mapping value="THIRDPARTY" channel="invokeUVMasterAPIChannel" />
</header-value-router>
<header-enricher input-channel="JuiceVendorMessageChannel"
output-channel="JuiceHeaderEnricherChannel">
<header name="sourceName" value="JUICE" />
</header-enricher>
And here is the gateway config:
I wanna know how to implement this config in java code? I searched google and found following code:
#Bean
public HeaderValueRouter headerRouter(String gatewayPrefix) {
HeaderValueRouter router = new HeaderValueRouter("METADATA_TYPE");
router.setChannelMapping("ASSEMBLY", "downloadImageToS3Channel");
router.setChannelMapping("THIRDPARTY", "invokeUVMasterAPIChannel");
router.setDefaultOutputChannel(new NullChannel());
router.setResolutionRequired(false);
return router;
}
#Bean
#Transformer(inputChannel="sdiVenderMessageChannel", outputChannel="sdiHeaderEnricherChannel")
public HeaderEnricher enrichHeaders() {
Map<String, HeaderValueMessageProcessor<?>> headersToAdd = new HashMap<String, HeaderValueMessageProcessor<?>>();
// TODO
//headersToAdd.put("sourceName",new StaticHeaderValueMessageProcessor<String>("SDI"));
headersToAdd.put("sourceName", null);
HeaderEnricher enricher = new HeaderEnricher(headersToAdd);
if(logger.isDebugEnabled()){
logger.debug("HeaderEnricher bean initial!");
}
return enricher;
}
But here are my questions:
1) how to config the 'input-channel' in java config?
2) Where should I invoke this function? When I start the application , the code doesn't run into this function. I know the headerValueRouter is used to dispatcher the message from input-channel to the output-channel, but what's the exact place that I can invoke this router? In the ConnectionFactory or ListenerContainer?
And here is the gateway I defined:
public void registerDynamicInboundGateway(DefaultListableBeanFactory beanFactory) {
this.beanFactory = beanFactory;
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition("org.springframework.integration.jms.JmsMessageDrivenEndpoint");
String jndiFactoryName = this.registerJndiObjectFactoryBean(gatewayPrefix, jmsQueueValue);
this.destination = jndiFactoryName;
String containerBeanName = this.registerMessageListenerContainer();
String listenerBeanName = this.registerMessageListener();
builder.addConstructorArgReference(containerBeanName);
builder.addConstructorArgReference(listenerBeanName);
setValueIfAttributeDefined(builder, autoStartup, "auto-startup");
String beanName = null;
if(gatewayPrefix.equals(HCC_GATEWAY_PREFIX)){
beanName = gatewayPrefix + DynamicInboundGateway.HCC_GATEWAY_SUFIX;
} else if (gatewayPrefix.equals(UVMASTER_GATEWAY_PREFIX)) {
beanName = gatewayPrefix + DynamicInboundGateway.UVMASTER_GATEWAY_PREFIX;
} else {
beanName = gatewayPrefix + DynamicInboundGateway.GATEWAY_SUFIX;
}
this.beanFactory.registerBeanDefinition(
beanName, builder.getBeanDefinition());
}
I felt confused and didn't found any sample code for this.
Thanks a lot!
When I define the HeaderEnricher according to the sample code in the spring-integration website like below:
#Bean
#Transformer(inputChannel="sdiVenderMessageChannel", outputChannel="sdiHeaderEnricherChannel")
public HeaderEnricher enrichHeaders() {
Map<String, HeaderValueMessageProcessor<?>> headersToAdd = new HashMap<String, HeaderValueMessageProcessor<?>>();
// TODO
headersToAdd.put("sourceName",new StaticHeaderValueMessageProcessor<String>("SDI"));
//headersToAdd.put("sourceName", null);
HeaderEnricher enricher = new HeaderEnricher(headersToAdd);
if(logger.isDebugEnabled()){
logger.debug("HeaderEnricher bean initial!");
}
return enricher;
}
And this occured some error:
StaticHeaderValueMessageProcessor cannot be resolved to a type
But I've import all the required packages with maven. I can not figure out why.
Hopefully, this simple Spring Boot app will make things clear...
#SpringBootApplication
public class So40585409Application {
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext context = SpringApplication.run(So40585409Application.class, args);
JmsTemplate template = context.getBean(JmsTemplate.class);
template.convertAndSend("foo", "message1", m -> {
m.setStringProperty("foo", "bar");
return m;
});
template.convertAndSend("foo", "message2", m -> {
m.setStringProperty("foo", "baz");
return m;
});
Thread.sleep(5000);
context.close();
}
#Bean
public JmsMessageDrivenEndpoint inbound(ConnectionFactory jmsConnectionFactory) {
return new JmsMessageDrivenEndpoint(container(jmsConnectionFactory), listener());
}
#Bean
public DefaultMessageListenerContainer container(ConnectionFactory jmsConnectionFactory) {
DefaultMessageListenerContainer container = new DefaultMessageListenerContainer();
container.setConnectionFactory(jmsConnectionFactory);
container.setDestinationName("foo");
return container;
}
#Bean
public ChannelPublishingJmsMessageListener listener() {
ChannelPublishingJmsMessageListener listener = new ChannelPublishingJmsMessageListener();
listener.setRequestChannelName("toRouter");
return listener;
}
#Bean
#Router(inputChannel="toRouter")
public HeaderValueRouter router() {
HeaderValueRouter router = new HeaderValueRouter("foo");
router.setChannelMapping("bar", "barChannel");
router.setChannelMapping("baz", "bazChannel");
return router;
}
#ServiceActivator(inputChannel = "barChannel")
public void bar(String in) {
System.out.println("Received via barChannel: " + in);
}
#ServiceActivator(inputChannel = "bazChannel")
public void baz(String in) {
System.out.println("Received via bazChannel: " + in);
}
}
Result:
2016-11-14 09:17:56.798 INFO 65082 --- [ main] com.example.So40585409Application : Started So40585409Application in 8.842 seconds (JVM running for 10.819)
Received via barChannel: message1
Received via bazChannel: message2
2016-11-14 09:18:02.038 INFO 65082 --- [ main] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext#2b546384: startup date [Mon Nov 14 09:17:49 EST 2016]; root of context hierarchy
EDIT - Header Enricher
I just added your bean with no problems...
#ServiceActivator(inputChannel = "barChannel2")
public void bar(String in, #Header("sourceName") String sourceName) {
System.out.println("Received via barChannel: " + in + " " + sourceName);
}
#ServiceActivator(inputChannel = "bazChannel")
public void baz(String in) {
System.out.println("Received via bazChannel: " + in);
}
#Bean
#Transformer(inputChannel = "barChannel", outputChannel = "barChannel2")
public HeaderEnricher enrichHeaders() {
Map<String, HeaderValueMessageProcessor<?>> headersToAdd = new HashMap<String, HeaderValueMessageProcessor<?>>();
headersToAdd.put("sourceName", new StaticHeaderValueMessageProcessor<String>("SDI"));
HeaderEnricher enricher = new HeaderEnricher(headersToAdd);
return enricher;
}
Result:
2016-11-15 09:00:48.383 INFO 50137 --- [ main] com.example.So40585409Application : Started So40585409Application in 1.814 seconds (JVM running for 2.528)
Received via barChannel: message1 SDI
Received via bazChannel: message2
2016-11-15 09:00:53.424 INFO 50137 --- [ main] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext#2c34f934: startup date [Tue Nov 15 09:00:46 EST 2016]; root of context hierarchy

Why spring bean can't be injected in quartz job?

I am now writing a quartz job to start at 3:00 am every day to save data in database and redis. But now I got a problem and can't get it solved even though I tried a lot of times.
The job:
public class QuartzScheduler implements ServletContextListener {
private static Logger logger = Logger.getLogger(QuartzScheduler.class);
#Autowired
private ExchangeRateConfigBean exchangeRateConfigBean;
private Scheduler scheduler = null;
#Override
public void contextInitialized(ServletContextEvent servletContext) {
try {
ExchangeRateConfig exchangeRateConfig = exchangeRateConfigBean.setUpConfigurationFromConfigFile();
if(!exchangeRateConfig.getJob_fire()) {
logger.info("ExchangeRate Job Info: Current Exchange Rate Job flag is not open. Wont start the job!");
return;
}
} catch (Exception e) {
logger.error("ExchangeRate Job Info: Something wrong when analyzing config.properties file!");
logger.error(e.getMessage());
logger.error(e.getStackTrace());
logger.error(e.getCause());
return;
}
try {
scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.start();
logger.info("ExchangeRate Job Info: Exchange Rate job starting......");
} catch (SchedulerException ex) {
logger.error(ex);
}
}
#Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
try {
scheduler.shutdown();
} catch (SchedulerException e) {
logger.error(e);
}
}
In this job , I autowired the component ExchangeRateConfigBean, but when I debugged in, I saw that the instance is null.
the spring config below:
<bean id="exchangeRateConfigBean" class="com.letv.exchangerate.bean.impl.ExchangeRateConfigBeanImpl">
<constructor-arg ref="exchangeRateErrorBean" />
</bean>
<bean id="exchangeRateErrorBean" class="com.letv.exchangerate.bean.impl.ExchangeRateErrorBeanImpl">
</bean>
The config Bean below:
public class ExchangeRateConfigBeanImpl implements ExchangeRateConfigBean {
public ExchangeRateConfigBeanImpl(){}
public ExchangeRateConfigBeanImpl(ExchangeRateErrorBean exchangeRateErrorBean)
{
this.exchangeRateErrorBean = exchangeRateErrorBean;
}
private static Logger logger = Logger.getLogger(ExchangeRateConfigBeanImpl.class.getClass());
private ExchangeRateErrorBean exchangeRateErrorBean;
#Override
public ExchangeRateConfig setUpConfigurationFromConfigFile() throws IOException {
InputStream inputStream = null;
ExchangeRateConfig exchangeRateConfig = null;
try {
Properties prop = new Properties();
String propFileName = "config.properties";
inputStream = getClass().getClassLoader().getResourceAsStream(propFileName);
exchangeRateConfig = new ExchangeRateConfig();
if (inputStream != null) {
prop.load(inputStream);
} else {
logger.error("property file '" + propFileName + "' not found in the classpath");
throw new FileNotFoundException("property file '" + propFileName + "' not found in the classpath");
}
String job_fire_tmp = prop.getProperty("job_fire");
exchangeRateConfig.setJob_fire(job_fire_tmp.isEmpty() ? false : Boolean.parseBoolean(job_fire_tmp));
return exchangeRateConfig;
} catch (IOException e) {
logger.error(e.getStackTrace());
return exchangeRateConfig;
} finally {
inputStream.close();
}
}
In the config bean, I used the constructor injection to inject the error bean above. the error bean's code lists below:
public class ExchangeRateErrorBeanImpl implements ExchangeRateErrorBean{
public ExchangeRateErrorBeanImpl(){}
#Override
public ExchangeRateError getExchangeRateError(String content) {
if (content.isEmpty())
return null;
if (!content.contains(":"))
return null;
String[] strArray = content.split(":");
return new ExchangeRateError(strArray[0], strArray[1]);
}
}
Anyone can help? why I autowired the Config bean in the job class, it will create null instance? thx.
And before I post this, I have read this in detail, Why is my Spring #Autowired field null?
but it didn't save my time.
Your code shows QuartzScheduler as an instance of ServletContextListener. This will only create a Java bean. Your Quartz Scheduler class must be a bean in a Spring applicationContext. Only then will the other dependencies be autowired. Refer this for example - http://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html#scheduling-quartz

How to make elasticsearch embedded accessible via localhost:9200

I am playing with spring-boot-sample-data-elastcisearch project.
I've changed the pom and added:
SampleElasticsearchApplicationWebXml extends SpringBootServletInitializer
to run with Tomcat embedded.
My application.properties has
spring.data.elasticsearch.http-enabled=true
spring.data.elasticsearch.local=true
I want to be able to connect to localhost:9200 in order to use elasticsearch-head or other JS client. What am I missing?
Thanks,
Milan
According to this ticket, you can now simply add this line to your configuration files:
spring.data.elasticsearch.properties.http.enabled=true
you should define this for yourself, because NodeClientFactoryBean has an option for http.enabled but ElasticSearchAutoConfiguration does not (yet) set it.
#Configuration
#EnableConfigurationProperties(ElasticsearchProperties.class)
public class ElasticsearchConfiguration implements DisposableBean {
private static Log logger = LogFactory.getLog(ElasticsearchConfiguration.class);
#Autowired
private ElasticsearchProperties properties;
private NodeClient client;
#Bean
public ElasticsearchTemplate elasticsearchTemplate() {
return new ElasticsearchTemplate(esClient());
}
#Bean
public Client esClient() {
try {
if (logger.isInfoEnabled()) {
logger.info("Starting Elasticsearch client");
}
NodeBuilder nodeBuilder = new NodeBuilder();
nodeBuilder
.clusterName(this.properties.getClusterName())
.local(false)
;
nodeBuilder.settings()
.put("http.enabled", true)
;
this.client = (NodeClient)nodeBuilder.node().client();
return this.client;
}
catch (Exception ex) {
throw new IllegalStateException(ex);
}
}
#Override
public void destroy() throws Exception {
if (this.client != null) {
try {
if (logger.isInfoEnabled()) {
logger.info("Closing Elasticsearch client");
}
if (this.client != null) {
this.client.close();
}
}
catch (final Exception ex) {
if (logger.isErrorEnabled()) {
logger.error("Error closing Elasticsearch client: ", ex);
}
}
}
}
}

Resources