自定义了一个注解 @EnableRedis, 用户在yml中配置了redis地址,再加上这个注解就自动生成redisService,
如果用@EnableRedis(import=RedisConfiguration.class), 在RedisConfiguration里定义@Bean方法只对一个redisService有效,而我们需要多个redisService实例,不能在RedisConfiguration的afterProperties()里取applicationContext,因为这个时候RedisConfiguration还没实例化,由此可知:@Bean是先取方法生成BeanDefinition,在具体需要注入bean的时候才会调用@Bean方法,这个时候RedisConfiguration才实例化,@Bean方法才被调用。
有没有可能用ImportBeanDefinitionRegistrar来实现呢? ImportBeanDefinitionRegistrar是BeanDefinition的注册类,这个时候没有什么被实例化了,但有一个特殊:那就是Environment对象,通过Environment对象获取yml文件,然后再注册到RedisService的BeanDefinition到Registry即可。
网上搜了一圈,发现结果很少,也说明没人这么用,不过这个时候可以投机取巧一波。
代码如下:
@Import({RedisProperties.class, RedisRegistrar.class})
public @interface EnableRedis {
}
public class RedisRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware {
private static final Logger logger = LoggerFactory.getLogger(RedisRegistrar.class);
private Environment environment;
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//ImportBeanDefinition比实例化bean要早,这里不能注入
final RedisProperties redisProperties = Binder.get(environment).bind("xxx.redis", RedisProperties.class).orElse(null);
if (redisProperties == null) {
return;
}
for (Map.Entry<String, RedisPoolConfig> entry : redisProperties.getInstances().entrySet()) {
final GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
genericBeanDefinition.setBeanClass(RedisServiceImpl.class);
genericBeanDefinition.getConstructorArgumentValues().addGenericArgumentValue(entry.getValue());
registry.registerBeanDefinition(entry.getKey(), genericBeanDefinition);
logger.info("注册redis service成功: {}, host={}", entry.getKey(), entry.getValue().getHost());
}
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
}
网友评论