需求场景
在系统运行时,根据不同的场景需要多个类实例。比如一个 Redis 类,需要传入不同的 Category(可以理解为 Key 前缀),从而实现多个 Redis 子类。
步骤一、自定义注解
1 2 3 4 5
| @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface CacheService { String category() default ""; }
|
可以设置为 String value() default "";
,使用时可以隐藏字段名。
步骤二、扫描属性上的注解
1 2
| Field[] fields = object.getClass().getDeclaredFields(); CacheService annotation = field.getAnnotation(CacheService.class);
|
步骤三、向容器注入 Bean
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| ConfigurableApplicationContext context = (ConfigurableApplicationContext) applicationContext;
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) context.getBeanFactory();
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(RedisService.class);
beanDefinitionBuilder.addPropertyValue("category", category); beanFactory.registerBeanDefinition(field.getName(), beanDefinitionBuilder.getBeanDefinition());
RedisService bean = (RedisService) applicationContext.getBean(field.getName()); field.setAccessible(true); field.set(object, bean);
|
步骤四、使用
1 2
| @CacheService(category = Constants.ORDER_DRIVER) private RedisService orderDriverCache;
|
示意图
全部示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| public class RedisService { @Resource(name = "redisNioClient") private SquirrelClient redisNioClient;
@Resource(name = "redisClient") private RedisStoreClient redisClient;
@Setter private String category; }
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface CacheService { String category() default ""; }
@Component @Slf4j public class CacheServiceAnnotation implements ApplicationListener<ContextRefreshedEvent> {
@Override public void onApplicationEvent(ContextRefreshedEvent event) { final ApplicationContext applicationContext = event.getApplicationContext();
Arrays.stream(applicationContext.getBeanDefinitionNames()) .map(applicationContext::getBean) .forEach(object -> { final Field[] fields = object.getClass().getDeclaredFields(); Arrays.stream(fields) .filter(field -> field.isAnnotationPresent(CacheService.class)) .forEach(field -> { final RedisService bean = getRedisService(applicationContext, field); try { field.setAccessible(true); field.set(object, bean); log.info("set field success, object: {}, bean: {}", object.getClass().getSimpleName(), field.getName()); } catch (IllegalAccessException e) { log.error("set field fail, object: {}, bean: {}", object.getClass().getSimpleName(), field.getName(), e); } }); }); }
private RedisService getRedisService(ApplicationContext applicationContext, Field field) { if (applicationContext.containsBeanDefinition(field.getName())) { return (RedisService) applicationContext.getBean(field.getName()); }
final CacheService annotation = field.getAnnotation(CacheService.class); final String category = annotation.category();
ConfigurableApplicationContext context = (ConfigurableApplicationContext) applicationContext; DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) context.getBeanFactory(); BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(RedisService.class);
beanDefinitionBuilder.addPropertyValue("category", category); beanFactory.registerBeanDefinition(field.getName(), beanDefinitionBuilder.getBeanDefinition());
RedisService bean = (RedisService) applicationContext.getBean(field.getName()); log.info("register Bean success, bean: {}", field.getName()); return bean; } }
|
参考资料:
Java获取类、方法、属性上的注解_根号三-CSDN博客_java 获取属性上的注解
使用自定义注解动态绑定多实现类实例
SpringBoot动态注入及操作Bean