代码之家  ›  专栏  ›  技术社区  ›  MeetJoeBlack

Spring访问从非bean类代理bean

  •  1
  • MeetJoeBlack  · 技术社区  · 6 年前

    我有一个SpringBean,它在方法上使用DropWizard度量注释来度量一些度量(请参见Parse方法):

    @Component
    public class Consumer extends AbstractConsumer {
    
      @Autowired
      private EventsService eventsService;
    
      private ExecutorService executor;
    
      @PostConstruct
      void init() throws Exception {
        executor = Executors.newFixedThreadPool(1);
    
        ConsumerEventsHandler consumer = new ConsumerEventsHandler(Arrays.asList("topic1"), this);
        executor.submit(consumer);
      }
    
      @Timed(name = CONSUMER_BATCH_PARSING_TIME, absolute = true)
      public void parse(ConsumerRecord<String, String> record) {
        String val = record.value();
        eventsService.parseToDB(val);
      }
    }
    

    正如您看到的,这个bean向执行器服务提交了一个新任务,该任务不是bean,但它需要对 消费者 bean重用其逻辑(请参见 consumer.parse(记录); 呼叫):

    public class ConsumerEventsHandler implements Runnable {
    
    private Consumer consumer;
    private List<String> topics;
    protected final KafkaConsumer<String, String> kafkaConsumer;
    
    public ConsumerEventsHandler(List<String> topics, Consumer consumer) {
        this.topics = topics;
        this.consumer = consumer;
        this.kafkaConsumer = new KafkaConsumer<>();
    }
    
    @Override
    public void run() {
        try {
            consumer.subscribe(topics);
            while (true) {
                ConsumerRecords<String, String> records = consumer.poll(Long.MAX_VALUE);
    
                for (ConsumerRecord<String, String> record : records) {
                    consumer.parse(record);
                }
            }
        } finally {
            consumer.close();
        }
    }
    
    }
    

    这里是metrics config(我使用“Ryantenney/metrics spring”lib):

    @Configuration
    @EnableMetrics(proxyTargetClass = true)
    @ComponentScan(basePackages = "com.inq")
    public class SsvpApiMetricsConfig extends MetricsConfigurerAdapter {
      @Resource
      private MetricRegistry registry;
    
      @PostConstruct()
      public void init() {
        configureReporters(registry);
      }
    
      @Override
      public void configureReporters(MetricRegistry metricRegistry) {
    
        registerReporter(JmxReporter.forRegistry(metricRegistry).
           inDomain("com.inq.metrics").build()).start();
      }
    }
    

    结果,我看到了 消费者 bean是代理的,但是 消费品供应商 包含对普通bean的引用,因为它在内部创建时 消费者的 @通过“new consumerEventsHandler(..)”的后构造方法 消费者 bean还没有被代理,我假设在代理之前调用了@postconstruct。

    我看到的唯一解决办法就是 消费者 每次在运行方法中通过applicationContext获取bean引用,而不是将引用存储在 消费品供应商 类变量。 还有其他的解决办法吗?

    1 回复  |  直到 6 年前
        1
  •  1
  •   Essex Boy    6 年前

    只需在非Spring类上创建一个静态

    public class ConsumerEventsHandler implements Runnable {
    
    private static Consumer consumer;
    private List<String> topics;
    protected final KafkaConsumer<String, String> kafkaConsumer;
    
    public ConsumerEventsHandler(List<String> topics) {
        this.topics = topics;
        this.kafkaConsumer = new KafkaConsumer<>();
    }
    
    public static setConsumer(Consumer consumer) {
        ConsumerEventsHandler.consumer = consumer;
    }
    

    然后在你的弹簧侧,你可以有:

      @PostConstruct()
      public void init() {
        configureReporters(registry);
        ConsumerEventsHandler.setConsumer(consumer);
      }