Reputation: 21616
I have spring bean class RedisRepo inside I am initialising my database connection with @PostConstruct:
@PostConstruct
public void init() {
logger.debug("RedisRepo, Init.");
client = new RedisClient(REDIS_HOST, REDIS_PORT);
...
}
I am creating this bean using java config at SpringConfiguration.class:
@Bean
@Scope("singleton")
public RedisRepo redisjRepo() {
return new RedisRepo();
}
I started to build Integration tests using Spring. I am using the same configuration class (SpringConfiguration.class) for tests:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = SpringConfiguration.class)
My Test class using embedded-redis so I need to init it right before I start my tests:
@Before
public void init() throws IOException {
//init embedded-redis
}
The problem is when I start the tests the @PostConstruct of the RedisRepo class executed before my integration-test init() class (past below) which leading me to null since my embedded redis hasnt initialised just yet.
How could I avoid it? Mybe I am not doing something right?
Thanks, ray.
Upvotes: 1
Views: 3124
Reputation: 24571
I would suggest to consider using spring Boot auto-configuration (@EnableAutoConfiguration
or @SpringBootApplication
) to initialize Redis connection. You can use these Spring Boot properties to customize Redis:
# REDIS (RedisProperties)
spring.redis.database= # database name
spring.redis.host=localhost # server host
spring.redis.password= # server password
spring.redis.port=6379 # connection port
spring.redis.pool.max-idle=8 # pool settings ...
spring.redis.pool.min-idle=0
spring.redis.pool.max-active=8
spring.redis.pool.max-wait=-1
spring.redis.sentinel.master= # name of Redis server
spring.redis.sentinel.nodes= # comma-separated list of host:port pairs
This would remove need for connection initialization in @PostConstruct
production code and you can just autowire your Redis related beans from context dusting testing.
EDIT1:
To populate Redis instance before testing method you can use @BeforeMethod
(using TestNg) or @Before
(using JUnit). To populate it before the test but after the context is initialized use @PostConstruct in test class.
EDIT2:
You asked on generic rule how to overcome need for initialization of resources in @PostConstruct
. I believe your problem is how you are wiring beans in your application.
Your @PostConstruct
initialization is done in other bean, where RedisClient
is stored as variable client
. I would argue that it most probably mixing of concerns. If you register RedisClient
bean into spring context this way:
@Bean
public RedisClient redisClient() {
RedisClient client = new RedisClient(REDIS_HOST, REDIS_PORT);
...
return client;
}
You can just autowire it into bean where you had @PostConstruct
initialization. You are also able to autowire it during test. If RedisClient
is not thread-safe, you may want to consider prototype or request scope for it.
With this approach, I extremely rarely use @PostConstruct
and use Spring IoC container to handle all the reusable resource instances.
Upvotes: 1