代码之家  ›  专栏  ›  技术社区  ›  Grim

场地的春季

  •  0
  • Grim  · 技术社区  · 5 年前

    INFLUX_DB_SERVER reportMemory 做了大量的工作,它构建了一个度量和执行调用 reportAll ,在没有流入的情况下,所有这些工作都是无用的。

    我能做的就是写一个方法 isWorkPossible 并在每次调用时调用该方法。那可能是接吻之后的事,但那违反了干燥。所以我喜欢用AOP来实现。

    /**
     * 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 回复  |  直到 5 年前
        1
  •  1
  •   kriegaex    5 年前

    作为 新罕布什特 已经说过了, @annotation(my.package.MyAnnotation) 解释了为什么在你的期望值上没有发生任何错误的注释。

    如果你想通过AOP找出一个类是否有一个带有特定注释的成员,你需要使用一个特殊的切入点,比如 hasfield(@MyAnnotation * *) switch to AspectJ . 如果您想通过 get(@MyAnnotation MyType *) set(@MyAnnotation MyType *) .

    my other answer here .

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

    您可以使用它们来执行方面建议,只要是合适的时候。在您的示例中,您还可以更容易地钩住 @PostConstruct 方法,前提是所有目标类都有其中一个。

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


    :我查看了你最新的问题更新。我不明白,对于一个非常简单的问题,这是一个非常精心设计的解决方案,也不是AOP解决的好案例。尽管我非常喜欢AOP,但我无法理解这种情况是一个跨领域的问题:

    • 它似乎只影响一个班级, InfluxDBReporter
    • 更糟糕的是,您将注释放在一个私有字段上,但是需要一个外部类(在本例中是一个方面)对它做出反应。虽然这在技术上可以用AspectJ实现,但这是一个糟糕的设计,因为您正在将私有信息泄露给外部。
    • KeySet

    即使假设你有更多的公共方法应该被跳过,如果你真的想坚持这种方法,我也会像这样设计AOP解决方案:

    • 添加方法 public boolean isConnectedToDB() { return !dbs.isEmpty(); }
    • @Around 建议并从那里调用boolean方法,只调用 joinPoint.proceed() 如果有任何联系。否则不要继续,而是什么也不做 void 方法)或返回一个伪结果,例如 null (非- 无效

    public void 方法或非空方法。

    INFLUX_DB_SERVER 但我不知道这是什么,因为我在你的代码中看不到它。

    我最不想让你注意到的一件事 @Pointcut @Before , @After , @周围 . 您希望执行的操作进入建议,而不是切入点。我建议您在尝试设计基于AOP的解决方案之前先学习AOP基础知识。