Search
Write a publication
Pull to refresh
0
0
Send message

У меня немного другое видение ситуации, проекты с небольшими нагрузками не заметят проблемы с кешем, потому что буферы будут успевать освобождаться, и память новая аллоцироваться не будет. А если создают какой-нибудь концепт, то он нужен здесь и сейчас, и большинство предпочтут ByteBuffer.wrap(byte[] data), потому что это проще.

Со средними проектами немного иначе, из них до высоких нагрузок доходят гораздо меньше, чем завершают свой жизненный цикл или остаются в средняках. И в какой-то момент, "jdk.nio.maxCachedBufferSize" может стать настоящим спасением, чтоб проект мог дожить своё время, или дать отсрочку на чтение Вашей статьи.

Денис, спасибо за отличную статью!

В методе получения временного буфера написано, что если размер запрашиваемого буфера превышает некий порог, то кеш не используется. Вы не пробовали запретить кеширование буферов, установив "jdk.nio.maxCachedBufferSize" в ноль, интересно, насколько это было бы применимо для средних нагрузок?

public static ByteBuffer getTemporaryDirectBuffer(int size) {
    // If a buffer of this size is too large for the cache, there
    // should not be a buffer in the cache that is at least as
    // large. So we'll just create a new one. Also, we don't have
    // to remove the buffer from the cache (as this method does
    // below) given that we won't put the new buffer in the cache.
    if (isBufferTooLarge(size)) {
        return ByteBuffer.allocateDirect(size);
    }
  ....

   /**
   * Returns the max size allowed for a cached temp buffers, in
   * bytes. It defaults to Long.MAX_VALUE. It can be set with the
   * jdk.nio.maxCachedBufferSize property. Even though
   * ByteBuffer.capacity() returns an int, we're using a long here
   * for potential future-proofing.
   */
  private static long getMaxCachedBufferSize() {
      String s = java.security.AccessController.doPrivileged(
          new PrivilegedAction<String>() {
              @Override
              public String run() {
                  return System.getProperty("jdk.nio.maxCachedBufferSize");
              }
          });

Видимо, я не смог донести до Вас свою мысль.

В Ваш синглтон всегда инжектится один, и только один экземпляр Bank. Только в случае использования proxyMode=TARGET_CLASS, инжектится не объект класса, а прокси. Вы всегда получаете один и тот же объект, когда вызываете метод синглтона getNewBank(), можете это проверить.

Пример ниже, в котором получены два экземпляра Bank через BankService, убеждаемся, что получили один и тот же экземпляр и вызываем дважды метод getInput() для обоих Bank. Было создано 4 реальных экземпляра Bank, по одному на каждый вызов метод. Остаётся вопрос, действительно ли разработчик хотел бы вызвать метод getInput() на 4 разных объектах, или же только на 2, как это видно в коде.

final BankService bankService = ctx.getBean(BankService.class);
final Bank bank1 = bankService.getBank();
final Bank bank2 = bankService.getBank();
if(Objects.equals(bank1, bank2)) {
    System.out.println("There is the same bank");
    IntStream.range(0, 2)
            .forEach(i -> {
                System.out.println(bank1.getInput());
                System.out.println(bank2.getInput());
            });
}
Результат выполнения

There is the same bank
Created new bank.
3dafc23c-ad22-4a05-96af-ec155cc9cd46
Created new bank.
e328e94f-3a62-44df-837f-df3c8f6fd440
Created new bank.
39381838-c273-4131-9a54-0e4736cf3155
Created new bank.
3f7dca89-15ef-49e8-b71f-4289790d51e3

В Вашем реализации, в синглтон внедряется не реальный объект класса, а прокси. И при каждом вызове его методов, прокси решает, создавать новый экземпляр класса для вызова или нет. То есть, в Вашем случае, при каждом вызове метода getInput(), прокси решил создавать новый объект. Вызовите метод getInput() на одном и том же прокси 100 раз, думаю, там будет создано гораздо больше экземпляров, чем 1.

Простой пример, получен один бин из Вашей реализации, и на одном и том же бине вызван 500 раз один и тот же метод, вывод по спойлером под кодом.

        final Bank bank = ctx.getBean(Bank.class);
        IntStream.range(0, 500)
                .forEach(i -> System.out.println(bank.getInput()));
Вывод кода выше

new bank created
356f5044-9117-4d2a-b67a-e7d1690cc84b
new bank created
53950529-5dfb-4c85-b95f-0e84f25b2108
new bank created
bcd131c0-09d8-49e7-ad2b-4331aac0cabf
new bank created
f8fa5bbe-ee93-42cb-ab16-e153a0a013ed
new bank created
5707d254-78e9-4bf5-85d6-4b842da36403
new bank created
648d3719-fb8b-4c39-b3af-ca1e9736a05d
new bank created
102b8341-5309-4dfc-9cb3-2d3e3717971d
new bank created
9e9e1189-7eb5-43cd-b9c8-b2438c0db6c9
new bank created
3b762b69-2746-4ef4-9a8e-36238129617b
new bank created
704b9894-47fa-420b-9c7f-b86e019bcebe
new bank created
9d1a519f-d841-4cb4-ace2-2fbcd0cb983d
new bank created
0e55e9a6-662e-4fed-b568-dd44abe5829d
new bank created
43162b6d-ed89-451a-9fce-cec798862d96
new bank created
427bcda1-6d2d-4cf0-8b1e-17aaaec1ebee

Всё же, внедрять Prototype лучше так, как описано в документации, например, имплементировать интерфейс ApplicationContextAware и вызывать context.getBean(Prototype.class).https://docs.spring.io/spring-framework/docs/3.0.0.M4/reference/html/ch03s04.html#beans-factory-method-injection

Information

Rating
Does not participate
Registered
Activity