为什么静态块中的代码会执行多次?

5

我在Spring Boot中创建了一个类,用于建立一个全局的javers对象,可以被所有类使用。以下是我的代码。

@Component
public class JaversInstance {

    public static final Javers javers;
    static
    {

        ConnectionProvider connectionProvider = new ConnectionProvider() {
            @Override
            public Connection getConnection() throws SQLException {
                String url = "any_url";
                Properties props = new Properties();
                props.setProperty("user", "test");
                props.setProperty("password", "test");
                DriverManager.getConnection(url, props);
                System.out.println("CONNECTION PROVIDER invoked");
                return DriverManager.getConnection(url, props);
            }
        };

        JaversSqlRepository sqlRepository = SqlRepositoryBuilder
                .sqlRepository()
                .withConnectionProvider(connectionProvider)
                .withDialect(DialectName.MYSQL).build();
        System.out.println("JAVERS instance creation");
        javers = JaversBuilder.javers().registerJaversRepository(sqlRepository).build();
    }

    private JaversInstance() {

    }

}

输出:

JAVERS instance creation
CONNECTION PROVIDER invoked
CONNECTION PROVIDER invoked
CONNECTION PROVIDER invoked
CONNECTION PROVIDER invoked
CONNECTION PROVIDER invoked
CONNECTION PROVIDER invoked
CONNECTION PROVIDER invoked
CONNECTION PROVIDER invoked
CONNECTION PROVIDER invoked

有人能告诉我这里发生了什么?为什么会调用getConnection()这么多次?这是某种重试吗?

1
除非你有非常好的理由,否则不要使用静态初始化器。将代码放在其他地方。 - Thorbjørn Ravn Andersen
@ThorbjørnRavnAndersen,您能否建议一种更好的方法来建立一个全局的javers对象,以便所有类都可以使用。先感谢您。 - a_good_human
2
你正在使用Spring,只需将其设置为单例Spring bean。在需要的地方注入它即可。 - Sotirios Delimanolis
2个回答

2
每当ConnectionProvider的匿名类被加载时,它就会发生多次。以下代码将帮助您更好地理解它:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class Main {
    static Comparator<Integer> comparator;
    static {
        comparator = new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                System.out.println("Hello");
                return 0;
            }
        };
    }

    public static void main(String[] args) {
        List<Integer> list = new ArrayList<Integer>();
        list.add(40);
        list.add(20);
        list.add(10);
        list.add(30);
        Collections.sort(list, comparator);
    }
}

输出:

Hello
Hello
Hello

我可以理解这个问题。但是在我的代码中,我只在初始化JaversSqlRepository时调用了connectionProvider一次。那么它是如何被多次调用的呢?您能否在这个情况下解释一下。 - a_good_human

1
尽管在静态块中实例化了 ConnectionProvider,但其重写的方法既不是 static(无法),也与静态块本身无关,而是与实例 connectionProvider 相关。
基本上,您实现了匿名类的一个方法。我想 ConnectionProvider 是一个接口,那么定义一个实现相同接口的类将有效地与您的代码相同:
static
{
    ConnectionProvider connectionProvider = new MyConnectionProvider();
}

getConnection方法的内部并未绑定到静态块,而是绑定到实例connectionProvider本身。由于从静态块中定义的实例多次调用该方法,因此会有多个调用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接