字段的Spring Aspect

我有一个要向 InfluxDB 报告的 bean。数据库在表中INFLUX_DB_SERVER注册了 InfluxDB。如果你看代码你会发现 MethodreportMemory做了很多工作,它构造了一个 Measurement 并做了 call 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);

            }

        }

    }



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


知道为什么吗?


九州编程
浏览 82回答 1
1回答

12345678_0001

正如JB Nizet已经说过的那样,@annotation(my.package.MyAnnotation)它旨在捕获方法上的注释,而不是字段上的注释,这解释了为什么您对任何事情发生的期望都是错误的。如果你想通过 AOP 找出一个类是否有一个带有特定注释的成员,你需要使用一个特殊的切入点,比如hasfield(@MyAnnotation * *). 但是这个切入点在 Spring AOP 中不可用,你需要切换到 AspectJ。get(@MyAnnotation MyType *)如果您想通过或拦截对此类字段的读/写访问,也是如此set(@MyAnnotation MyType *)。AspectJ 还提供了特殊的切入点在类加载后拦截类的静态初始化 - >staticinitialization()拦截构造函数执行->MyType.new()只要是合适的时间,您就可以使用它们来执行您的方面建议。@PostConstruct在您的示例中,如果很明显所有目标类都有其中一个,您还可以更轻松地挂接到方法中。我的回答很笼统,因为你没有详细解释你到底想做什么。所以请随时提出后续问题。更新:我检查了你最新的问题更新。我不明白,这是针对一个非常简单的问题的非常人为的解决方案,也不是 AOP 解决的好案例。尽管我很喜欢 AOP,但我看不出这种情况是一个横切关注点:它似乎只影响一个类,InfluxDBReporter.您正在使用一个注释,该注释的存在唯一目的是告诉一个方面要做什么。更糟糕的是,您将注释放在私有字段上,但期望外部类(在本例中为方面)对其作出反应。虽然这在技术上使用 AspectJ 是可行的,但它是糟糕的设计,因为您将私有信息泄漏到外部。通过从您的示例类中跳过公共方法,您不会保存任何昂贵的与数据库相关的操作,因为迭代一个空KeySet意味着什么都不会发生,因此也不会有任何与数据库相关的错误。这里唯一真正发生的是构建器调用。它们应该很便宜。即使假设你有更多应该跳过的公共方法,如果你确实想坚持使用这种方法,我实际上会设计这样的 AOP 解决方案:向您的应用程序类添加一个方法public boolean isConnectedToDB() { return !dbs.isEmpty(); }。在您方面,使用@Around建议并从那里调用布尔方法,仅joinPoint.proceed()在有任何连接时才调用。否则不要继续,而是什么也不做(对于void方法)或返回一个虚拟结果null(对于非void方法)。确切的解决方案取决于您是否只有这个类或多个具有类似要求的类,如果您只有public void方法或非空方法。此外,您提到INFLUX_DB_SERVER但我不知道这是什么,因为我在您的代码中的任何地方都看不到它。最后但并非最不重要的一点是:我刚刚注意到您希望在 . 注释的方法中发生某些事情@Pointcut。抱歉,即使切入点没有错,那里也会发生一些事情,因为切入点定义只是用于实际的建议方法,例如@Before, @After, @Around。您想要执行的操作进入通知,而不是进入切入点。我建议您在尝试设计基于 AOP 的解决方案之前先学习 AOP 基础知识。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java