Spring bean内的Firebase初始化未触发onDataChange

dev*_*747 5 java firebase-realtime-database firebase-admin

我正在为Java使用Firebase管理员SDK。当我创建一个Java控制台应用程序时,下面的代码可以按预期工作。但是,如果我在springboot应用程序中的Bean初始化中放入相同的代码,则它永远不会进入onDataChange EventHandler内部。

我什至尝试在结尾放置足够延迟的Thread.sleep(),以检查是否正在发生这种情况,因为初始化bean的线程正在退出。但是,这没有帮助。

在spring bean中执行此操作的正确方法是什么?

import com.google.auth.oauth2.GoogleCredentials;
import com.google.firebase.FirebaseApp;
import com.google.firebase.FirebaseOptions;
import com.google.firebase.database.*; 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Repository;

import java.io.File;
import java.io.FileInputStream;
import java.util.HashMap;
import java.util.Map;

@Repository
@EnableAsync
public class MyBean {


    FirebaseDatabase db;


    public MyBean() {

        try {

            File file = new File(
                    getClass().getClassLoader().getResource("myKey.json").getFile()
            );

            FileInputStream fis = new FileInputStream(file);

            FirebaseOptions options = new FirebaseOptions.Builder()
                    .setCredentials(GoogleCredentials.fromStream(fis))
                    .setDatabaseUrl("https://myUrl/")
                    .build();

            FirebaseApp.initializeApp(options);

            db = FirebaseDatabase.getInstance();

            DatabaseReference ref = db
                    .getReference("/a/b/c");


            ref.addValueEventListener(new ValueEventListener() {
            //The code execution never comes in here

                public void onDataChange(DataSnapshot dataSnapshot) {
                    System.out.println("dataSnapshot.exists() :"+ dataSnapshot.exists()); 
                }


                public void onCancelled(DatabaseError error) {
                    System.out.print("Error: " + error.getMessage());
                }
            });

           // Thread.sleep(10000);

        } catch (Exception ex) {
            String err=ex.getMessage();
        }


    }

`
Run Code Online (Sandbox Code Playgroud)

Geo*_*rge -1

看一下该方法的源码FirebaseReference.getReference()

public DatabaseReference getReference() {
  return new DatabaseReference(ensureRepo(), Path.getEmptyPath());
}
Run Code Online (Sandbox Code Playgroud)

DatabaseReference每次你调用它时它都会创建一个新的。您现在执行此操作的方式是将 a 添加ValueEventListener到 a 中DatabaseReference,该 a 只会被垃圾收集,因为您没有以某种方式将其传递出此方法。

我建议将您的DatabaseReference对象声明为类中的 bean @Configuration

@Configuration
public class FirebaseConfig {

  // This is just the ApplicationContext, injected through abstraction 
  private final ResourceLoader resourceLoader;

  @Autowired // Constructor injection, recommended above field and setter injections
  public FirebaseConfig(ResourceLoader resourceLoader) {
    this.resourceLoader = resourceLoader;
  }

  @Bean
  public FirebaseDatabase firebaseDatabase() throws IOException {
    Resource resource = resourceLoader.getResource("classpath:myKey.json");
    InputStream inputStream = resource.getInputStream();
    FirebaseOptions firebaseOptions = new FirebaseOptions.Builder()
            .setCredentials(GoogleCredentials.fromStream(inputStream))
            .setDatabaseUrl("url")
            .build();
    FirebaseApp.initializeApp(firebaseOptions);
    return FirebaseDatabase.getInstance();
  }

  @Bean
  public DatabaseReference databaseReference(FirebaseDatabase firebaseDatabase) {
    DatabaseReference ref = firebaseDatabase.getReference();
    ref.addValueEventListener(new ValueEventListener() {

      public void onDataChange(DataSnapshot dataSnapshot) {
        System.out.println("dataSnapshot.exists() :" + dataSnapshot.exists());
      }


      public void onCancelled(DatabaseError error) {
        System.out.print("Error: " + error.getMessage());
      }
    });

    return ref;
  }
}
Run Code Online (Sandbox Code Playgroud)

现在,在整个 Spring 应用程序中,您应该自动装配这个 DatabaseReference bean。

一个更优雅的解决方案是将其分离ValueEventListener到它自己的 bean 中,并将其自动装配到DatabaseReferencebean 方法中:

  @Bean
  public DatabaseReference databaseReference(
    FirebaseDatabase firebaseDatabase, 
    // List injection will be populated with all ValueEventListener beans in the ApplicationContext
    List<ValueEventListener> valueEventListeners 
  ) {
    DatabaseReference ref = firebaseDatabase.getReference();
    valueEventListeners.forEach(ref::addValueEventListener);
    return ref;
  }
Run Code Online (Sandbox Code Playgroud)

在一个单独的类中:

@Component
public class SystemOutListener implements ValueEventListener {
  @Override
  public void onDataChange(DataSnapshot snapshot) {
    System.out.println("dataSnapshot.exists() :"+ snapshot.exists());
  }

  @Override
  public void onCancelled(DatabaseError error) {
    System.out.print("Error: " + error.getMessage());
  }
}
Run Code Online (Sandbox Code Playgroud)