我读到CDI自定义扩展一些文件,并读取该链接类似属性装载机一些示例代码: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;
}
}
更新的/ proc / meminfo中后,现在我的问题是memUsed属性没有改变。 怎么了 ? 可以创建动态的CDI扩展为做到这一点? 注1:我复制和粘贴整个我的代码。 注2:的/ proc / meminfo中是在支承proc文件系统Linux与Unix操作系统使用的存储器的信息。
扩大评论,让我先说喷射时,每一个bean实例,只有一次。所以他们不会自动给出,以适应他们的一生中会发生变化的可能性每范围豆类通常创建一次。我能想到的两件事情:
原理很简单(在observer pattern)。我不知道如何跟踪在/ 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
}
}
供应商是一个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
,再考虑潜在的低效率的服务。