Свойство динамического обновления расширения CDI - PullRequest
0 голосов
/ 05 февраля 2019

Я читаю некоторые документы о пользовательских расширениях CDI и читаю несколько примеров кодов, таких как Properties loader, по этим ссылкам: Link-A - Link-B .

Я написал простое расширение CDI, как эти коды.

public class SystemStatisticExtension implements Extension {

    public <T> void processInjectionTarget(@Observes ProcessInjectionTarget<T> pit) {
        AnnotatedType<T> at = pit.getAnnotatedType();
        InjectionTarget<T> it = pit.getInjectionTarget();
        if (at.isAnnotationPresent(Monitor.class)) {
            pit.setInjectionTarget(new MemoryInjectionPoint<>(it, at));
        }
    }
}

и это моя реализация InjectionPointTarget:

public class MemoryInjectionPoint<T> implements InjectionTarget<T> {

    private InjectionTarget<T> it;
    private AnnotatedType<T> at;
    private int kB = 1024;
    private int mB = kB / 1024;
    private int gB = mB / 1024;

    public MemoryInjectionPoint(InjectionTarget<T> it, AnnotatedType<T> at) {
        this.it = it;
        this.at = at;
    }

    @Override
    public void inject(T instance, CreationalContext<T> ctx) {
        it.inject(instance, ctx);
        int swapUsed = SystemPropertiesLoader.newInstance().getSwapUsed();
        Set<AnnotatedField<? super T>> annotatedFields = at.getFields();
        for (AnnotatedField<? super T> annotatedField : annotatedFields) {
            if (annotatedField.isAnnotationPresent(Memory.class)) {
                int memUsed = SystemPropertiesLoader.newInstance().getMemUsed();
                Memory memory = annotatedField.getAnnotation(Memory.class);
                Unit u = memory.unitType();
                switch (u) {
                    case KILOBYTE:
                        setFieldMemValue(instance, memUsed / kB, annotatedField);
                        break;
                    case MEGABYTE:
                        setFieldMemValue(instance, memUsed / mB, annotatedField);
                        break;
                    case GIGABYTE:
                        setFieldMemValue(instance, memUsed / gB, annotatedField);
                        break;
                }
            }
            if (at.isAnnotationPresent(Swap.class)) {
                Memory memory = annotatedField.getAnnotation(Memory.class);
                Unit u = memory.unitType();
                switch (u) {
                    case kILOBYTE:
                        setFieldSwapValue(instance, swapUsed / kB, annotatedField);
                        break;
                    case MEGABYTE:
                        setFieldSwapValue(instance, swapUsed / mB, annotatedField);
                        break;
                    case GIGABYTE:
                        setFieldSwapValue(instance, swapUsed / gB, annotatedField);
                        break;
                }
            }
        }
    }

    private void setFieldMemValue(T instance, int memUsed, AnnotatedField<? super T> annotatedField) {
        try {
            Field field = annotatedField.getJavaMember();
            field.setAccessible(true);
            field.setInt(instance, memUsed);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    private void setFieldSwapValue(T instance, int swapUsed, AnnotatedField<? super T> annotatedField) {
        try {
            Field field = annotatedField.getJavaMember();
            field.setAccessible(true);
            field.setInt(instance, swapUsed);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void postConstruct(T instance) {
        it.postConstruct(instance);
    }

    @Override
    public void preDestroy(T instance) {
        it.preDestroy(instance);
    }

    @Override
    public T produce(CreationalContext<T> ctx) {
        return it.produce(ctx);
    }

    @Override
    public void dispose(T instance) {
        it.dispose(instance);
    }

    @Override
    public Set<InjectionPoint> getInjectionPoints() {
        return it.getInjectionPoints();
    }
}

это мой SystemPropertiesLoader:

public class SystemPropertiesLoader {
    private static Supplier<Stream<String>> supplier;

    private SystemPropertiesLoader() {

    }

    public static SystemPropertiesLoader newInstance() {
        supplier = () -> {
            Stream<String> lines = Stream.empty();
            try {
                lines = Files.lines(Paths.get("/proc/meminfo"));
            } catch (IOException e) {
                e.printStackTrace();
            }
            return lines;
        };
        return new SystemPropertiesLoader();
    }

    public int getMemTotal() {
        return Integer.valueOf(
                supplier.get()
                        .findFirst()
                        .orElse("")
                        .split(":")[1]
                        .trim()
                        .replace(" kB", ""));
    }

    public int getMemFree() {
        return Integer.valueOf(
                supplier.get()
                        .skip(1)
                        .findFirst()
                        .orElse("")
                        .split(":")[1]
                        .trim()
                        .replace(" kB", ""));
    }

    public int getSwapTotal() {
        return Integer.valueOf(supplier.get()
                .skip(14)
                .findFirst()
                .orElse("")
                .split(":")[1]
                .trim()
                .replace(" kB", ""));
    }

    public int getSwapFree() {
        return Integer.valueOf(supplier.get()
                .skip(15)
                .findFirst()
                .orElse("")
                .split(":")[1]
                .trim()
                .replace(" kB", ""));
    }

    public int getMemUsed() {
        return getMemTotal() - getMemFree();
    }

    public int getSwapUsed() {
        return getSwapTotal() - getSwapFree();
    }
} 

и аннотации:

@Target({FIELD, PARAMETER})
@Retention(RUNTIME)
public @interface Memory {
    Unit unitType() default Unit.MEGABYTE;
}

@Target({METHOD,TYPE})
@Retention(RUNTIME)
public @interface Monitor {
}

и это мой используемый случай:

@Monitor
public class MemoryMonitor {

    @Memory
    private int memUsed;

    public int getMemUsed() {
        return memUsed;
    }
}

Теперь моя проблема заключается в том, что свойство memUsed не изменяется после обновления / proc / meminfo.
Что не так?
Может ли для этого создать динамическое расширение CDI??
Примечание 1: Я копирую и вставляю весь свой код.
Примечание 2: / proc / meminfo - это информация о памяти, используемой в поддерживаемых операционных системах Linux и Unix. Файловая система proc.

1 Ответ

0 голосов
/ 06 февраля 2019

Расширяя комментарий, позвольте мне сначала сказать, что инъекция происходит только один раз за экземпляр компонента.Бобы обычно создаются один раз для каждой области, поэтому им автоматически не дают возможности адаптироваться к изменениям, которые происходят в течение их жизни.Я могу думать о двух вещах:

1) Использование событий для уведомления заинтересованных сторон об изменениях

Принцип прост ( шаблон наблюдателя ).Я не знаю, как отследить изменения в / proc / meminfo (достаточно ли java.nio.file.WatchService?), Но если вы обнаружили изменение, выдается событие:

public class MemInfoEvent {
    private int memUsed;
    // constructor and getter
}

Когда вы чувствуетеДля изменения вызовите следующий компонент:

import javax.enterprise.event.Event;
...

@ApplicationScoped
public class MemInfoEventEmitter {
    @Inject
    private Event<MemInfo> memInfoEvent;

    public void handleMemInfoChange(int memUsed) {
        memInfoEvent.fire(new MemInfoEvent(memUsed));
    }
}

И наблюдайте за изменением, где это необходимо:

public class BeanInterestedInMemChanges {
    public void memInfoChanged(@Observes MemInfoEvent e) {
        // do what you must
    }
}

2) Используйте java.util.function.IntSupplier (или эквивалентный)

Поставщик - это компонент CDI, который знает, как получить memUsed, например:

@ApplicationScoped
public class MemUsedSupplier implements IntSupplier {
    private SystemPropertiesLoader systemPropertiesLoader = ...; // could be injected, if this is more appropriate

    @Override
    public int getAsInt() {
        return systemPropertiesLoader.getMemUsed();
    }
}

ПРИМЕЧАНИЕ. Реализация, приведенная выше, может быть неэффективной!Используйте в качестве отправной точки - подтверждение концепции! Неэффективность слишком часто читает / proc / meminfo, если часто вызывается getAsInt().Возможно, вы захотите реализовать какое-то кэширование / регулирование.

Вы можете даже реализовать MemoryMonitor в терминах SystemPropertiesLoader, опять же заботясь о потенциальной неэффективности.

...