当前位置: 首页 > 知识库问答 >
问题:

现场的Spring纵横

龙哲
2023-03-14

我有一个bean要向InfluxDB报告。数据库在表中有注册的INFLUX\u DB\u服务器。如果你看一下代码,你会发现方法reportMemory做了很多工作,它构造了一个测量和do调用,当没有InfluxDB时,所有这些工作都是无用的。

所以我们的想法是,如果没有影响数据库,就跳过这项工作。由于公共无效方法不返回值,它对周围的应用程序没有影响。

我能做的是编写一个方法isWorkPossible,并在每次调用时调用该方法。这可能是接吻之后的事,但这违反了干涸。所以我喜欢使用AOP对其进行归档。

但是如果没有注册influxdb,我喜欢跳过所有公共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 {
    }
}

我期望系统。出来println在bean被实例化但它没有被实例化时运行。

知道为什么吗?

共有1个答案

彭宏深
2023-03-14

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

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

有关更多详细信息,请参阅我的另一个答案。

AspectJ还提供了特殊的切入点

  • 在类加载后拦截类的静态初始化-

只要时机合适,您可以使用它们来执行方面建议。在您的示例中,如果很明显所有目标类都有一个方法,那么您还可以更容易地连接到PostConstruct方法。

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

更新:我查看了你最新的问题更新。我不明白,对于一个非常简单的问题,这是一个非常人为的解决方案,也不是AOP可以解决的好案例。虽然我很喜欢AOP,但我无法理解这种情况是如何成为一个跨领域的问题:

  • 它似乎只影响一个类,InfluxDBReporter
  • 您使用的注释的唯一目的是告诉一个方面要做什么
  • 更糟糕的是,您将注释放在一个私有字段上,但希望外部类(在本例中是一个方面)对其作出反应。虽然在AspectJ中这在技术上是可能的,但这是一种糟糕的设计,因为您正在将私人信息泄露给外界
  • 通过从示例类中跳过公共方法,您不会保存任何昂贵的与DB相关的操作,因为在空键集上迭代意味着什么也不会发生,因此也不会出现任何与DB相关的错误。这里唯一真正发生的事情是生成器调用。它们应该便宜

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

  • 添加一个方法public boolean isConnectedToDB(){return!dbs.isEmpty();} 到应用程序类
  • 在您的方面中,使用一个关于的建议并从那里调用布尔方法,只调用连接点。如果有任何连接,请继续()。否则,不要继续,而是什么也不做(对于void方法)或返回类似于null的伪结果(对于非void方法)

如果您只有公共void方法或非void方法,则精确解取决于您是只有这一类还是有多个具有类似需求的类。

此外,您提到的是INFLUX\u DB\u服务器,但我不知道这是什么,因为我在您的代码中的任何地方都看不到它。

最后,但并非最不重要的一点:我刚刚注意到,您希望在由切入点注释的方法中发生一些事情。很抱歉,即使切入点没有错,也会发生这种情况,因为切入点定义仅用于实际的通知方法中,例如前后前后左右。您希望执行的操作进入建议,而不是切入点。我建议您在尝试设计基于AOP的解决方案之前,先学习AOP基础知识。

 类似资料:
  • 问题内容: 需要一些帮助,我刚刚开始学习Spring,似乎无法弄清楚我们的错: Application.java-没有包 User.java-包com.mapping UserDAO.java-包com.accesors Root.java-包com.controllers 当我运行项目时,我似乎得到了以下启示 堆栈跟踪: 据我了解,这意味着@ComponentScan没有检测到软件包 问题答案:

  • 我正在使用一个Udemy教程学习Spring Boot,它跳过了如何将Spring工具安装到我们的IDE,所以我一直在谷歌自己如何做。 我想把它添加到我现有的Eclipse Jee Oxygen IDE中,因为我在它上面安装了其他的LANG和工具,我想把它全部保存在一个地方。 我试着通过Eclipse中的Marketplace向导搜索它,但它没有出现。 我还尝试了使用Eclipse.com的mar

  • 一面10.11三人一起面 自我介绍,问项目,项目的问题有点怪 怎么给前端传数据 讲分布式锁,下单问题 为什么用b+ linux常用命令 二面10.17问项目三人一起面 自我介绍,说项目,redis怎么解决一人一单问题(我说了分布式锁面试官好像不满意) 为什么选择java,为什么选择我们公司 反问 感受:二面的时候大佬很多,才知道因为它必解决北京户口。感觉国企更喜欢男生…

  • 我对Guice的理解是: 构造函数级注入()意味着每次通过

  • 本文向大家介绍python实现图片横向和纵向拼接,包括了python实现图片横向和纵向拼接的使用技巧和注意事项,需要的朋友参考一下 本文实例为大家分享了python实现图片横向和纵向拼接的具体代码,供大家参考,具体内容如下 直接上代码: 结果: 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持呐喊教程。

  • 我在响应式站点上设置了flexSlider。我正在创建的滑块可以拍摄横向和纵向图像。我设置了,以便调整高度以适应图像。 在最大的媒体查询中,flexslider容器的宽度为750px。这对于横向图像很好,但纵向图像太大了。肖像图像的宽度设置为与容器相同的大小-750px宽,因此高度至少是容器宽度的两倍,因此如果不滚动,则无法查看整个图像。 在css中,我尝试设置最大高度:750px,这解决了高度问