Java創建實例方法的區別

近來打算自己封裝一個比較方便讀寫的Office Excel 工具類,前面已經寫了一些,比較粗糙本就計劃重構一下,剛好公司的電商APP後臺原有的導出Excel實現出現了可怕的性能問題,600行的數據生成Excel工作簿居然需要50秒以上,客戶端連接都被熔斷了還沒導出來,挺巧,那就一起解決吧。

對於消息中間件RabbitMQ,想必各位小夥伴沒有用過、也該有聽過,它是一款目前市面上應用相當廣泛的消息中間件,可以實現消息異步通信、業務服務模塊解耦、接口限流、消息分發等功能,在微服務、分佈式系統架構中可以說是充當着一名了不起的角色!(詳細的介紹,Debug在這裏就不贅述了,各位小夥伴可以上官網看看其更多的介紹及其典型的應用場景)!

在本篇博文中,我們將使用RabbitMQ充當消息發送的組件,將它與後面篇章介紹的“郵件服務”結合實現“用戶秒殺成功後異步發送郵件通知消息,告知用戶秒殺已經成功!”,下面我們一起進入代碼實戰吧。

在上一個版本里呢,我認爲比較巧妙的地方在於用函數式編程的方式代替反射,很早以前瞭解了反射的一些底層後我就知道反射的性能很差,但一直沒實際測試過各種調用場景的性能差距。

至於底層字節碼、CPU指令這些我就不深究了,我還沒到那個級別,那這次就來個簡單的測試吧。

目標:創建Man對象。

方式:

① 直接引用 new Man();

② 使用反射

③ 使用內部類

④ 使用Lombda表達式

⑤ 使用Method Reference

在學習Java8新特性的時候,我所瞭解到的是Lombda表達式是內部類的一種簡化書寫方式,也就是語法糖,但兩者間在運行時居然有比較明顯的性能差距,讓我不得不懷疑它底層到底是啥東西,時間精力有限先記着,有必要的時候再去啃openJDK吧。

還有就是Lombda和Method Reference從表現來看,底層應該是同一個東西,但IDEA既然分開兩種內部類的寫法推薦,那就分開對待吧。

測試時每種方式循環調用 1 億次,每種方式連續計算兩次時間,然後對比第二次運行的結果,直接run沒有采用debug運行。

貼代碼:

緊接着,我們藉助SpringBoot天然具有的一些特性,自動注入RabbitMQ一些組件的配置,包括其“單一實例消費者”配置、“多實例消費者”配置以及用於發送消息的操作組件實例“RabbitTemplate”的配置:

//通用化 Rabbitmq 配置
@Configuration
public class RabbitmqConfig {
  private final static Logger log = LoggerFactory.getLogger(RabbitmqConfig.class);

  @Autowired
  private Environment env;

  @Autowired
  private CachingConnectionFactory connectionFactory;

  @Autowired
  private SimpleRabbitListenerContainerFactoryConfigurer factoryConfigurer;

  //單一消費者
  @Bean(name = "singleListenerContainer")
  public SimpleRabbitListenerContainerFactory listenerContainer(){
      SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
      factory.setConnectionFactory(connectionFactory);
      factory.setMessageConverter(new Jackson2JsonMessageConverter());
      factory.setConcurrentConsumers(1);
      factory.setMaxConcurrentConsumers(1);
      factory.setPrefetchCount(1);
      factory.setTxSize(1);
      return factory;
  }

  //多個消費者
  @Bean(name = "multiListenerContainer")
  public SimpleRabbitListenerContainerFactory multiListenerContainer(){
      SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
      factoryConfigurer.configure(factory,connectionFactory);
      factory.setMessageConverter(new Jackson2JsonMessageConverter());
      //確認消費模式-NONE
      factory.setAcknowledgeMode(AcknowledgeMode.NONE);
      factory.setConcurrentConsumers(env.getProperty("spring.rabbitmq.listener.simple.concurrency",int.class));
      factory.setMaxConcurrentConsumers(env.getProperty("spring.rabbitmq.listener.simple.max-concurrency",int.class));
      factory.setPrefetchCount(env.getProperty("spring.rabbitmq.listener.simple.prefetch",int.class));
      return factory;
  }

  @Bean
  public RabbitTemplate rabbitTemplate(){
      connectionFactory.setPublisherConfirms(true);
      connectionFactory.setPublisherReturns(true);
      RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
      rabbitTemplate.setMandatory(true);
      rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
          @Override
          public void confirm(CorrelationData correlationData, boolean ack, String cause) {
              log.info("消息發送成功:correlationData({}),ack({}),cause({})",correlationData,ack,cause);
          }
      });
      rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
          @Override
          public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
              log.warn("消息丟失:exchange({}),route({}),replyCode({}),replyText({}),message:{}",exchange,routingKey,replyCode,replyText,message);
          }
      });
      return rabbitTemplate;
  }
}

直接查看實現,會發現 onSubscribe() 中做了一些判斷,比如 82 104 等幾行都是做了一些 同步 異步 等的判斷,然後初始化 Disposable , onSubscribe() 是上游 Observable 完成了整條訂閱鏈之後調用的,所以這些操作是在開始訂閱之後才初始化操作,然後 106 行可以看出把一個包裝處理過的 Disposable 傳遞給下游。

查看一下這個scheduler的worker,會發現worker的基類schedule()方法是相同的互相調用的,所以可以直接看多個參數的schedule(),可以看到 73 行創建了一個 ScheduledRunnable 對象,並且把 主線程的handler 以及外面的 Observer 傳遞過去,接着 82 行用主線程的handler發送消息, 119 行 ScheduledRunnable 裏的 run 被調用,接着 Observer也就是runnable 也調用 run方法

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章