Could not find default ScheduledExecutorService bean with Redis and Spring - spring

I have just develop a configuration with Spring Session and Redis, everything work fine, but in my console logs, I got
2015-06-29 15:45:44,088 [main] DEBUG org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor - Could not find default ScheduledExecutorService bean
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.scheduling.TaskScheduler] is defined
How can I configure ScheduledExecutorService bean?
Update :
#Configuration
#EnableRedisHttpSession
#Conditional(RedisDeclarationCondition.class)
public class LocalRedisConfig extends WebMVCConfig{
#Value("${redis.host}")
private String host;
#Value("${redis.port}")
private String port;
#Bean
public JedisConnectionFactory connectionFactory() {
return new JedisConnectionFactory();
}
#Bean
public RedisConnectionFactory jedisConnectionFactory(){
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxIdle(5);
poolConfig.setMaxTotal(10);
poolConfig.setMinIdle(1);
poolConfig.setTestOnBorrow(true);
poolConfig.setTestOnReturn(true);
poolConfig.setTestWhileIdle(true);
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(poolConfig);
// RedisOperationsSessionRepository cleanup = new RedisOperationsSessionRepository(jedisConnectionFactory);
//optional
//jedisConnectionFactory.setHostName(host);
//jedisConnectionFactory.setPort(Integer.valueOf(port));
return jedisConnectionFactory;
}
#Bean
public StringRedisTemplate redisTemplate(){
StringRedisTemplate redisTemplate = new StringRedisTemplate(jedisConnectionFactory());
return redisTemplate;
}

it is a DEBUG message, could be ignored by set your logging.level.org.springframework=INFO
Using #Scheduled and #EnableScheduling but gives NoSuchBeanDefinitionException

Related

Confusion about "No qualifying bean of type...RedisConnectionFactory"

Since the different configs, I have written two LettuceConnectionFactory:
ItemFactoryConfig
ActivityFactoryConfig
the code as follows:
#Configuration
#PropertySource(value = "classpath:config/redis.properties", encoding = "UTF-8")
public class ItemFactoryConfig {
#Value("${item.host}")
private String host;
#Value("${item.port}")
private int port;
#Bean
public LettuceConnectionFactory itemFactory(){
RedisStandaloneConfiguration redisConfiguration = new RedisStandaloneConfiguration();
redisConfiguration.setHostName(host);
redisConfiguration.setPort(port);
return new LettuceConnectionFactory(redisConfiguration);
}
}
#Configuration
#PropertySource(value = "classpath:config/redis.properties", encoding = "UTF-8")
public class ActivityFactoryConfig {
#Value("${activity.host}")
private String host;
#Value("${activity.port}")
private int port;
#Bean
public LettuceConnectionFactory activityFactory(){
RedisStandaloneConfiguration redisConfiguration = new RedisStandaloneConfiguration();
redisConfiguration.setHostName(host);
redisConfiguration.setPort(port);
return new LettuceConnectionFactory(redisConfiguration);
}
}
And I added #Qualifier when these LettuceConnectionFactories were autowired.
#Configuration
public class ItemTemplateConfig {
#Autowired
#Qualifier("itemFactory")
private LettuceConnectionFactory itemFactory;
#Bean
public RedisTemplate<String, String> itemTemplate(){...}
}
#Configuration
public class ActivityTemplateConfig {
#Autowired
#Qualifier("activityFactory")
private LettuceConnectionFactory activityFactory;
#Bean
public RedisTemplate<String, String> activityTemplate(){...}
}
However, spring boot still report the NoUniqueBeanDefinitionException.
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'org.springframework.data.redis.connection.RedisConnectionFactory' available: expected single matching bean but found 2: activityFactory,itemFactory
Spring boot Description:
Parameter 0 of method redisTemplate in org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration required a single bean, but 2 were found:
- activityFactory: defined by method 'activityFactory' in class path resource [com/lyf/redisdemo/config/Activity/ActivityFactoryConfig.class]
- itemFactory: defined by method 'itemFactory' in class path resource [com/lyf/redisdemo/config/Item/ItemFactoryConfig.class]
Action:
Consider marking one of the beans as #Primary, updating the consumer to accept multiple beans, or using #Qualifier to identify the bean that should be consumed
spring boot: 2.1.0.RELEASE

How to using annotation #RefreshScope with spingboot : connectionFactory?

how to refresh connectionFactory or connectionpool,such as dataSource,JedisConnectionFactory... when the springboot application is running?
(I used springcould-config to update my configs)
#Bean
#ConfigurationProperties(prefix = "spring.redis.pool")
public JedisPoolConfig getRedisConfig() {
JedisPoolConfig config = new JedisPoolConfig();
return config;
}
#Bean(name = "redisConnection")
public JedisConnectionFactory getConnectionFactory() {
JedisConnectionFactory factory = new JedisConnectionFactory();
JedisPoolConfig config = getRedisConfig();
factory.setPoolConfig(config);
factory.setPassword(password);
factory.setHostName(hostName);
factory.setPort(port);
factory.setDatabase(database);
return factory;
}
...
pseudocode:
onChangeListener function then
refreshScope.refresh("redisConnection");
but it does not work,however, some files with #Value("${spring.redis.host}")
it change

Unit Test Error creating bean with name "amqAdmin" while testing spring integration TCP component

I'm writing a sidecar micro service that talks TCP to a legacy app and uses rabbitMQ on the other side. I'm just getting started and writing tests as I go along to better understand how everything works as I'm new to Spring. My app builds, deploys, and runs fine.
However, writing clean tests has been a bit more complicated. I have been patterning my code off the spring-integration tcp basic examples. I started with having a mock TCPServer to test my code defined outside my test class. But the mock TCPServer kept being built for every test class. So I moved it into the TCPGatewayTest class similar to the example I found.
This led to some missing bean issues which led me to add a #ContextConfiguration annotation which has gotten me further. But now I have other missing beans. I'm sure I'm messing up my ApplicationContext with #ContextConfiguration. Is there a better way of doing this with a different annotation or doing it slightly different? I'm not going the xml route and would like to steer clear of it if possible.
The familiar no qualifying bean error:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.amqp.rabbit.connection.ConnectionFactory' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
My Test Class is the following
package org.inc.imo;
#ComponentScan("org.inc")
#ContextConfiguration(classes = {TCPGatewayTest.TCPServerMock.class,
org.inc.imo.Configuration.TCPConfig.class,
org.inc.imo.Configuration.RabbitConfig.class })
#TestPropertySource(locations= "classpath:test.properties")
#RunWith(SpringRunner.class)
#SpringBootTest
public class TCPGatewayTest {
#Autowired
private TCPGateway gateway;
#Autowired
AbstractServerConnectionFactory crLfServer;
#Before
public void setup() {
TestingUtilities.waitListening(this.crLfServer, 10000L);
}
#Test
public void testConnectionToMockServer() {
String result = gateway.send("Hello World");
assertEquals("HELLO WORLD", result);
}
#Configuration
#MessageEndpoint
public static class TCPServerMock {
#Value("${imo.port}")
private int port;
#Bean()
public AbstractServerConnectionFactory serverCF() {
return new TcpNetServerConnectionFactory(this.port);
}
#Transformer(inputChannel="fromTcp", outputChannel="toEcho")
public String convert(byte[] bytes) {
return new String(bytes);
}
#ServiceActivator(inputChannel="toEcho")
public String upCase(String in) {
return in.toUpperCase();
}
#Bean
public TcpInboundGateway tcpInGate(AbstractServerConnectionFactory connectionFactory) {
TcpInboundGateway inGate = new TcpInboundGateway();
inGate.setConnectionFactory(connectionFactory);
inGate.setRequestChannel(fromTcp());
return inGate;
}
#Bean
public MessageChannel fromTcp() {
return new DirectChannel();
}
}
}
Rabbit Config Class
package org.inc.imo.configuration;
#EnableIntegration
#IntegrationComponentScan
#ComponentScan
#Configuration
public class RabbitConfig {
public final static String IMO_REQUEST_JEA = "imo.request.jea";
public final static String IMO_REQUEST_INFO = "imo.request.info";
#Bean
public AmqpAdmin amqpAdmin(final ConnectionFactory connectionFactory) {
RabbitAdmin admin = new RabbitAdmin(connectionFactory);
admin.declareQueue(jeaRequestQueue());
admin.declareQueue(infoRequestQueue());
return admin;
}
#Bean
public Queue jeaRequestQueue() {
return new Queue(IMO_REQUEST_JEA);
}
#Bean
public Queue infoRequestQueue() {
return new Queue(IMO_REQUEST_INFO);
}
#Bean
public RabbitTemplate rabbitTemplate(final ConnectionFactory connectionFactory) {
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
return rabbitTemplate;
}
#Bean
public ObjectWriter objectWriter() {
return new ObjectMapper().writer();
}
}
TCPConfig class
package org.inc.imo.configuration;
#EnableIntegration
#IntegrationComponentScan
#ComponentScan
#Configuration
public class TCPConfig {
#Value("${imo.hostname}")
private String host;
#Value("${imo.port}")
private int port;
private static MessageChannel sendChannel;
private static MessageChannel replyChannel;
#Bean
public MessageChannel replyChannel() {
replyChannel = new DirectChannel();
return replyChannel;
}
#Bean(name="sendChannel")
public MessageChannel sendChannel() {
MessageChannel directChannel = new DirectChannel();
sendChannel = directChannel;
return directChannel;
}
#Bean
public TcpNetClientConnectionFactory connectionFactory() {
TcpNetClientConnectionFactory connectionFactory = new TcpNetClientConnectionFactory(host, port);
connectionFactory.setSingleUse(false);
return connectionFactory;
}
#Bean
#ServiceActivator(inputChannel = "sendChannel")
public TcpOutboundGateway tcpOutboundGateway() {
TcpOutboundGateway tcpOutboundGateway = new TcpOutboundGateway();
tcpOutboundGateway.setConnectionFactory(connectionFactory());
tcpOutboundGateway.setReplyChannel(this.replyChannel());
tcpOutboundGateway.setRequiresReply(true);
return tcpOutboundGateway;
}
}
TCPGateway Interface
package org.inc.imo.Domain;
#MessagingGateway(defaultRequestChannel = "sendChannel")
public interface TCPGateway {
String send(String message);
}
The exception is like:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.amqp.rabbit.connection.ConnectionFactory' available: expected at least 1 bean which qualifies as autowire candidate.
And the suffered bean is like:
#Bean
public AmqpAdmin amqpAdmin(final ConnectionFactory connectionFactory) {
RabbitAdmin admin = new RabbitAdmin(connectionFactory);
admin.declareQueue(jeaRequestQueue());
admin.declareQueue(infoRequestQueue());
return admin;
}
So, you request here org.springframework.amqp.rabbit.connection.ConnectionFactory bean injection, but there is no one.
If you simply test against the local RabbitMQ, there is just enough to add one more bean:
#Bean
ConnectionFactory connectionFactory() {
return new CachingConnectionFactory();
}
and your AmqpAdmin will be able to connect there.

SpringBoot Elasticache JedisMovedDataException: MOVED

Trying to use SpringBoot with SpringData with Elasticache:
application.properties:
spring.redis.host=XXXX-dev.XXXX.clusXXXcfg.XXX.cache.amazonaws.com
spring.redis.port=6379
CacheConfiguration:
#Configuration
#PropertySource("classpath:application.properties")
public class CacheConfiguration {
#Value("${spring.redis.host}")
private String redisHostName;
#Bean
public RedisTemplate<String, Company> redisTemplate() {
RedisTemplate<String, Company> template = new RedisTemplate();
template.setConnectionFactory(jedisConnectionFactory());
return template;
}
#Bean
JedisConnectionFactory jedisConnectionFactory() {
JedisConnectionFactory factory = new JedisConnectionFactory();
factory.setHostName(redisHostName);
factory.setUsePool(true);
return factory;
}
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
Service call:
#Autowired
RedisTemplate<String, Company> redisTemplate;
private ValueOperations valueOperations;
#PostConstruct
private void init() {
valueOperations = redisTemplate.opsForValue();
}
#Override
public String createOtp(Company company) {
String token = UUID.randomUUID().toString();
valueOperations.set(token, company);
valueOperations.getOperations().expire(token, 5, TimeUnit.MINUTES);
return token;
}
Error:
org.springframework.data.redis.ClusterRedirectException: Redirect: slot 7228 to 10...:6379.*
redis.clients.jedis.exceptions.JedisMovedDataException: MOVED 7228 10...:6379.*
The question is - what is wrong with configuration?
You're running your Elasticache in Redis Cluster mode (only Redis Cluster responds with MOVED) but the connection factory is configured in standalone mode.
Spring Boot can auto-configure all the things you've set up manually for you. Basically, remove your CacheConfiguration class (or at least remove the majority of code):
#Configuration
public class CacheConfiguration {
#Bean
public RedisTemplate<String, Company> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Company> template = new RedisTemplate();
template.setConnectionFactory(connectionFactory);
return template;
}
}
And then configure the following properties in your application.properties file:
spring.redis.cluster.nodes=<node_host>:<port> # Comma-separated list of "host:port" pairs to bootstrap from.
Spring Boot loads application.properties by default and the Redis auto-config configures a RedisTemplate<Object, Object> bean by default. Specializing beans is a valid use-case – do not duplicate what's already provided by the auto-config, especially if you want to achieve what auto-config does.
See also:
Common application properties
Externalized Configuration

Error using Spring AOP with Dynamic Proxy with JMS Template on Weblogic 12.2.1

I'm getting an error when I try to use in the same project Spring Template JMS to messaging to ActiveMQ and Spring AOP to auditing and handle exceptions on Weblogic 12.2.1. Error occurs on server startup.
If I config aspect to use CGLIB, I got exceptions from Weblogic, and I prefer, if it's possible to maintain using of Dynamic Proxy. Does anyone already had this problem or have any idea what could cause it?
My aspect config class:
#Configuration
#EnableAspectJAutoProxy
#lombok.extern.slf4j.Slf4j
public class AspectConfig {
#Bean
public LoggingErrorAspect loggingErrorAspect(){
return new LoggingErrorAspect();
}
}
Message Listener config class:
#Configuration
#EnableJms
#lombok.extern.slf4j.Slf4j
public class MessagingListenerConfig {
#Autowired
ConnectionFactory connectionFactory;
#Bean
public JmsListenerContainerFactory<?> jmsListenerContainerFactory() {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
factory.setConcurrency("1-1");
return factory;
}
}
Stack:
weblogic.application.ModuleException:
org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean
named
'org.springframework.jms.config.internalJmsListenerEndpointRegistry'
is expected to be of type
'org.springframework.jms.config.JmsListenerEndpointRegistry' but was
actually of type 'com.sun.proxy.$Proxy213'
You don't show where you are injecting the JmsListenerEndpointRegistry (or RabbitTemplate) but you have to inject by interface when you proxy with JDK proxies.
Why are you advising the registry - what are you trying to achieve with that? It doesn't provide many interfaces so it can't be referenced once proxied, except by DisposableBean and SmartLifecycle.
The RabbitTemplate can be proxied but you need to inject RabbitOperations, not RabbitTemplate.
I fix it the problem. I had to change the broker to AMQP RabbitMQ, and I needed to use interface instead of classes in all my config. After it, startup load works and aspect too.
Here is Aspect Config and Messaging Config.
AspectConfig:
#Configuration
#EnableAspectJAutoProxy
#lombok.extern.slf4j.Slf4j
public class AspectConfig {
#Bean
public LoggingErrorAspect loggingErrorAspect(){
return new LoggingErrorAspect();
}
}
MessagingConfig:
#Configuration
#PropertySources({ #PropertySource("classpath:/config/messaging.properties") })
#ComponentScan("br.com.aegea.scab.notification")
#lombok.extern.slf4j.Slf4j
public class MessagingConfig {
public static final String ERROR_QUEUE = "ERROR_QUEUE";
public static final String EMAIL_QUEUE = "EMAIL_QUEUE";
#Autowired
private Environment environment;
#Bean
public ConnectionFactory connectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory(environment.getProperty("spring.rabbitMQ.host"));
connectionFactory.setUsername(environment.getProperty("spring.rabbitMQ.user"));
connectionFactory.setPassword(environment.getProperty("spring.rabbitMQ.password"));
return connectionFactory;
}
#Bean
public MessageConverter jsonMessageConverter() {
return new JsonMessageConverter();
}
#Bean
public RabbitOperations emailRabbitTemplate() {
RabbitTemplate template = new RabbitTemplate(connectionFactory());
template.setRoutingKey(EMAIL_QUEUE);
template.setMessageConverter(jsonMessageConverter());
return template;
}
#Bean
public MessageListenerContainer listenerContainer() {
SimpleMessageListenerContainer listenerContainer = new SimpleMessageListenerContainer();
listenerContainer.setConnectionFactory(connectionFactory());
listenerContainer.setQueueNames(EMAIL_QUEUE);
listenerContainer.setMessageConverter(jsonMessageConverter());
listenerContainer.setMessageListener(messageReceiver());
listenerContainer.setAcknowledgeMode(AcknowledgeMode.AUTO);
return listenerContainer;
}
#Bean
public MessageListener messageReceiver() {
return new MessageReceiver();
}
}

Resources