Как Молекула делает поиск ролей

Итак, у нас есть ситуация, когда нам нужно статически получить объект класса или полное / простое имя класса без явного использования синтаксиса MyClass.class.

В некоторых случаях это может быть очень удобно, например logger для функций верхнего уровня (в этом случае kotlin создает статический класс Java, недоступный из кода kotlin).

У нас есть несколько разных вариантов для получения этого info:

  1. new Object(){}.getClass().getEnclosingClass();, отмеченный Том Хотин - галтика
  2. getClassContext()[0].getName(); из SecurityManager, отмеченный Кристоффер
  3. new Throwable().getStackTrace()[0].getClassName(); count ludwig
  4. Thread.currentThread().getStackTrace()[1].getClassName(); из Keksi
  5. и наконец, удивительный MethodHandles.lookup().lookupClass(); из Rein

Я подготовил бенчмарк для всех вариантов и результатов:

# Run complete. Total time: 00:04:18

Benchmark                                                      Mode  Cnt      Score     Error  Units
StaticClassLookup.MethodHandles_lookup_lookupClass             avgt   30      3.630 ±   0.024  ns/op
StaticClassLookup.AnonymousObject_getClass_enclosingClass      avgt   30    282.486 ±   1.980  ns/op
StaticClassLookup.SecurityManager_classContext_1               avgt   30    680.385 ±  21.665  ns/op
StaticClassLookup.Thread_currentThread_stackTrace_1_className  avgt   30  11179.460 ± 286.293  ns/op
StaticClassLookup.Throwable_stackTrace_0_className             avgt   30  10221.209 ± 176.847  ns/op

Выводы

  1. Лучший вариант использования, довольно чистый и чудовищно быстрый. Доступно только с Java 7 и Android API 26!
 MethodHandles.lookup().lookupClass();
  1. Если вам нужна эта функция для Android или Java 6, вы можете использовать второй лучший вариант. Это довольно быстро, но создает анонимный класс в каждом месте использования: (
 new Object(){}.getClass().getEnclosingClass();
  1. Если вам это нужно во многих местах и ​​вы не хотите, чтобы ваш байткод набухал из-за тонны анонимных классов - SecurityManager - ваш друг (третий вариант). Но вы не можете просто называть getClassContext() - он защищен в классе SecurityManager. Вам понадобится вспомогательный класс:
 // Helper class
 public final class CallerClassGetter extends SecurityManager
 {
    private static final CallerClassGetter INSTANCE = new CallerClassGetter();
    private CallerClassGetter() {}

    public static Class getCallerClass() {
        return INSTANCE.getClassContext()[1];
    }
 }

 // Usage example:
 class FooBar
 {
    static final Logger LOGGER = LoggerFactory.getLogger(CallerClassGetter.getCallerClass())
 }
  1. Вам, вероятно, никогда не нужно использовать последние два варианта на основе getStackTrace() из исключения или Thread.currentThread(). Очень неэффективно и может возвращать только имя класса как String, а не экземпляр Class<*>.

PS

Если вы хотите создать экземпляр регистратора для статического kotlin utils (например, я :), вы можете использовать этот помощник:

import org.slf4j.Logger
import org.slf4j.LoggerFactory

// Should be inlined to get an actual class instead of the one where this helper declared
// Will work only since Java 7 and Android API 26!
@Suppress("NOTHING_TO_INLINE")
inline fun loggerFactoryStatic(): Logger
    = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass())

Пример использования:

private val LOGGER = loggerFactoryStatic()

/**
 * Returns a pseudo-random, uniformly distributed value between the
 * given least value (inclusive) and bound (exclusive).
 *
 * @param min the least value returned
 * @param max the upper bound (exclusive)
 *
 * @return the next value
 * @throws IllegalArgumentException if least greater than or equal to bound
 * @see java.util.concurrent.ThreadLocalRandom.nextDouble(double, double)
 */
fun Random.nextDouble(min: Double = .0, max: Double = 1.0): Double {
    if (min >= max) {
        if (min == max) return max
        LOGGER.warn("nextDouble: min $min > max $max")
        return min
    }
    return nextDouble() * (max - min) + min
}

0
задан Kevin C 19 March 2019 в 14:39
поделиться

1 ответ

Molecule делает это, устанавливая некоторые разумные значения по умолчанию для ANSIBLE_ROLES_PATH: Нажмите меня для исходного кода

Существует также концепция «каталог проекта» , каталог, из которого запускается молекула. Это будет каталог вашей роли.

0
ответ дан Kevin C 19 March 2019 в 14:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: