从自动配置创建Autowireable @Beans

时间:2017-11-16 12:37:06

标签: java spring spring-boot autowired

相关:

此问题与this几乎相同,但使用BeanFactoryAware的答案并不能解决我的问题,因为创建的@Bean不是@Autowireable。

要求:

  • 通过弹簧配置配置bean数量;
  • 通过@ConfigurationProperties;
  • 选择此配置
  • 创造&根据来自自动配置模块的配置注入@Beans;
  • 能够@Autowire在应用程序中创建bean。

实施例: 可以通过spring配置声明基于咖啡因的Cache @Beans的数量。以下是基于类似问题的接受答案的实施:

首先,启动自动配置模块:

@Component
@ConfigurationProperties
@Data
public class Props {

    private LocalCacheConf cache = new LocalCacheConf();

    @Data
    public static class LocalCacheConf {

        /**
        * List of caches to create, with accompanying configuration.
        */
        private List<CacheDef> caches = new ArrayList<>();

        @Data
        public static class CacheDef {

            private String name;
            private CaffeineCacheConf properties;
        }

        @Data
        public static class CaffeineCacheConf {

            private long maximumSize = -1;
        }
    }
}


@Configuration
@Slf4j
public class LocalCacheConfig implements BeanFactoryAware {

    @Autowired private Props props;
    @Setter private BeanFactory beanFactory;
    private CaffeineCacheManager localCacheManager;

    @PostConstruct
    public void configure() {
        setCacheManager();
        createCaches( props.getCache() );
    }

    private void createCaches( LocalCacheConf locCacheConf ) {
        ConfigurableBeanFactory configurableBeanFactory = (ConfigurableBeanFactory) beanFactory;

        for ( CacheDef cacheProps : locCacheConf.getCaches() ) {
            Cache cache = createAndConfigureCache(
                    cacheProps.getName(),
                    cacheProps.getProperties()
            );
            configurableBeanFactory.registerSingleton( cacheProps.getName(), cache );
        }
    }

    private Cache createAndConfigureCache( String name, CaffeineCacheConf props ) {
        Caffeine<Object, Object> c = Caffeine.newBuilder().recordStats();

        if ( props.getMaximumSize() >= 0 ) {
            c.maximumSize( props.getMaximumSize() );
        }
        // can extend config to include additional properties

        localCacheManager.setCaffeine( c );
        log.info( "building [{}] cache with config: [{}]", name, c.toString() );

        return localCacheManager.getCache( name );
    }

    private void setCacheManager() {
        log.info( "creating {}...", "localCacheManager" );
        localCacheManager = new CaffeineCacheManager();
        ( (ConfigurableBeanFactory) beanFactory )
                .registerSingleton( "localCacheManager", localCacheManager );
    }
}

最后,using应用程序将通过配置定义其缓存(yaml here):

cache:
  caches:
    - name: c1
      properties:
        maximumSize: 50
    - name: c2
      properties:
        maximumSize: 5000

此示例基于类似问题的答案,但是以这种方式创建的缓存@Beans无法在应用程序中自动装配。

ImportBeanDefinitionRegistrar中注册bean定义的感觉可能会起作用,但不要认为beanDefs可以与Caffeine实例一起使用,因为这些实例是通过构建器创建的,而不是属性设置器。

如何实施?