gpt4 book ai didi

java - 田野的 Spring 方面

转载 作者:行者123 更新时间:2023-12-02 09:38:20 29 4
gpt4 key购买 nike

我有一个 Bean 需要向 InfluxDB 报告。数据库在表 INFLUX_DB_SERVER 中注册了 InfluxDB。如果你看一下代码,你会发现方法reportMemory做了很多工作,它构造了一个Measurement并调用reportAll,当有没有 InfluxDB。

因此,如果没有 InfluxDB,我们的想法是跳过这项工作。由于 public-void-methods 不返回值,因此对周围的应用程序没有影响。

我可以做的是编写一个方法 isWorkPossible 并在每次调用时调用该方法。这可能遵循 KISS 但违反了 DRY。所以我喜欢使用 AOP 来归档它。

但如果没有注册 InfluxDB,我喜欢跳过所有 public void 方法的执行。

/**
* The reporter to notify {@link InfluxDB influxDBs} for changes.
*/
@Named
public class InfluxDBReporter {
/**
* Logger for reporting. For security reasons neither the username nor the
* password should be logged above {@link Level#FINER}.
*/
private static final Logger LOG = Logger.getLogger(InfluxDBReporter.class.getCanonicalName());

/**
* The entitymanager to use, never <code>null</code>.
*/
@PersistenceContext
private final EntityManager entityManager = null;

/**
* The registred {@link InfluxDBServer} in key and the URL in value.
*/
@SkipPublicVoidMethodsIfEmpty
private final Map<InfluxDB, URL> dbs = new LinkedHashMap<>();

/**
* Initializes the connections.
*/
@PostConstruct
private void connect() {
for (InfluxDBServer db : FROM(囗InfluxDBServer.class).all(entityManager)) {
try {
URL dbUrl = new URL(db.getUrl());
InfluxDB idb = InfluxDBFactory.connect(db.getUrl(), db.getUsername(), db.getPassword());
idb.setDatabase(db.getDatabaseName());
dbs.put(idb, dbUrl);
} catch (MalformedURLException e) {
LOG.log(Level.SEVERE, db.getUrl(), e);
}
}
}

/**
* Closes all connections to all {@link InfluxDB}.
*/
@PreDestroy
private void disconnect() {
for (InfluxDB influxDB : dbs.keySet()) {
try {
influxDB.close();
} catch (Exception e) {
// Fault barrier
LOG.log(Level.WARNING, "InfluxDBServer URL: " + dbs.get(idb), e);
}
}
}

/**
* Report memory statistics.
*
* @param availableProcessors Amount of available processors, never negative.
* @param totalMemory The total memory, never negative.
* @param maxMemory The max memory, never negative.
* @param freeMemory The free memory, never negative.
*/
public void reportMemory(int availableProcessors, long totalMemory, long maxMemory, long freeMemory) {
reportAll(Point.measurement("jvm").addField("totalMemory", totalMemory).addField("maxMemory", maxMemory)
.addField("freeMemory", freeMemory));
}

/**
* Report a point to all connected {@link InfluxDBServer}.
*
* @param builder The point to report.
*/
private void reportAll(Builder builder) {
Point infoPoint = builder.time(System.currentTimeMillis(), TimeUnit.MILLISECONDS).build();
for (InfluxDB idb : dbs.keySet()) {
new Thread(() -> {
try {
idb.write(infoPoint);
} catch (Exception e) {
// Fault barrier
LOG.log(Level.WARNING, "InfluxDBServer URL: " + dbs.get(idb), e);
throw e;
}
}).start();
}
}
}

这是我的方面:

@Aspect
public class MethodAnnotations {
@Pointcut("@annotation(xxx.MethodAnnotations.SkipPublicVoidMethodsIfEmpty)")
private void anyOldTransfer(JoinPoint jp) {
System.out.println(jp); <----- never executed.
}

public @interface SkipPublicVoidMethodsIfEmpty {
}
}

我希望 System.out.println 在 bean 实例化时运行,但它没有。

知道为什么吗?

最佳答案

正如 JB Nizet 已经说过的,@annotation(my.package.MyAnnotation) 旨在捕获方法上的注释,而不是字段上的注释,这解释了为什么您期望发生任何事情都是错误的。

如果你想通过AOP找出一个类是否有一个带有特定注释的成员,你需要使用一个特殊的切入点,比如hasfield(@MyAnnotation * *)。但是这个切入点在Spring AOP中不可用,你需要switch to AspectJ 。如果您想通过 get(@MyAnnotation MyType *)set(@MyAnnotation MyType *) 拦截对此类字段的读/写访问,情况也是如此。

有关更多详细信息,请参阅my other answer here .

AspectJ 还提供特殊的切入点

  • 在类加载后拦截类的静态初始化 -> staticinitialization()
  • 拦截构造函数执行 -> MyType.new()

您可以在适当的时候使用它们来执行您的方面建议。在您的示例中,如果很明显所有目标类都具有其中之一,您还可以更轻松地连接到 @PostConstruct 方法。

我的回答很笼统,因为您没有详细解释您到底想做什么。因此,请随时提出后续问题。

<小时/>

更新:我查看了您最新的问题更新。我不明白,这是针对一个非常简单的问题的非常人为的解决方案,也不是 AOP 解决的好案例。尽管我非常喜欢 AOP,但我不明白这种情况如何成为一个跨领域的关注点:

  • 它似乎只影响一个类,InfluxDBReporter
  • 您使用的注释的唯一目的是告诉某个方面要做什么。
  • 更糟糕的是,您将注释放在私有(private)字段上,但期望外部类(在本例中是一个方面)对其使用react。虽然 AspectJ 在技术上可以做到这一点,但这是一个糟糕的设计,因为您正在将私有(private)信息泄露到外部。
  • 通过跳过示例类中的公共(public)方法,您不会保存任何昂贵的与数据库相关的操作,因为迭代空的KeySet意味着什么都不会发生,因此也不会有任何数据库相关错误。这里真正发生的唯一事情是构建器调用。它们应该很便宜。

即使假设您有更多应该跳过的公共(public)方法,如果您确实想坚持使用该方法,我实际上也会像这样设计 AOP 解决方案:

  • 添加一个方法 public boolean isConnectedToDB() { return !dbs.isEmpty(); } 到您的应用程序类。
  • 在您的方面,使用@Around建议并从那里调用 boolean 方法,仅在存在任何连接时调用joinPoint.proceed()。否则,不要继续,而是不执行任何操作(对于 void 方法)或返回虚拟结果,例如 null(对于非 void 方法)。

确切的解决方案取决于您是否只有一个类或具有类似需求的多个类(如果您只有 public void 方法或还有非 void 方法)。

此外,您提到了INFLUX_DB_SERVER,但我不知道这是什么,因为我在代码中的任何地方都看不到它。

最后但并非最不重要的一点:我刚刚注意到您期望在由 @Pointcut 注释的方法中发生一些事情。抱歉,即使切入点没有错误,那里也会发生一些事情,因为切入点定义只是在实际的建议方法中使用,例如 @Before@After@Around。您想要执行的操作将进入建议,而不是进入切入点。我建议您在尝试设计基于 AOP 的解决方案之前先学习 AOP 基础知识。

关于java - 田野的 Spring 方面,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57324555/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com