我有一个要向InfluxDB报告的bean。表INFLUX_DB_SERVER
中的数据库已注册InfluxDB。如果看一下代码,您会发现方法reportMemory
做了大量的工作,它构造了一个Measurement并调用了reportAll
,在没有InfluxDB的情况下,所有这些工作都是无用的。
因此,如果没有InfluxDB,则想法是跳过该工作。由于public-void-methods不返回值,因此对周围的应用程序没有影响。
我能做的是编写一个方法isWorkPossible
,并在每次调用时都调用该方法。可能在KISS之后,但违反了DRY。因此,我喜欢使用AOP将其存档。
但是,如果没有注册InfluxDB,我想跳过所有公共无效方法的执行。
/**
* 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时运行,但不会实例化。
知道为什么吗?
答案 0 :(得分:1)
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
。KeySet
进行迭代意味着什么都不会发生,因此也就不会有任何与DB相关的错误。真正发生的唯一事情是构建器调用。它们应该便宜。即使假设您还有许多应该跳过的公共方法,但如果您确实愿意使用这种方法,我实际上会设计这样的AOP解决方案:
public boolean isConnectedToDB() { return !dbs.isEmpty(); }
。@Around
建议并从那里调用boolean方法,仅在存在任何连接时才调用joinPoint.proceed()
。否则,不要继续执行,而是什么也不做(对于void
方法),或者返回像null
这样的虚拟结果(对于非{void
方法)。确切的解决方案取决于您是否只有这一类或具有相似要求的多个类(如果您只有public void
方法或非无效方法)。
此外,您还提到INFLUX_DB_SERVER
,但我不知道这是什么,因为我无法在您的代码中的任何地方看到它。
最后但并非最不重要的一点:我只是注意到您期望@Pointcut
注释的方法中会发生某些事情。抱歉,即使切入点没错,也会在这里发生什么事情,因为切入点定义仅用于实际的建议方法中,例如@Before
,@After
,@Around
。您要执行的操作进入建议,而不是切入点。建议您在尝试设计基于AOP的解决方案之前先学习AOP基础知识。