Инициализация Firebase внутри Spring Bean не запускается на DataChange - PullRequest
5 голосов
/ 07 октября 2019

Я использую Firebase Admin SDK для Java. Когда я создал консольное приложение Java, этот код ниже работает, как ожидалось. Но если я добавлю тот же код при инициализации bean-компонента в приложении Springboot, он никогда не попадет внутрь onDataChange EventHandler.

Я даже пытался поместить Thread.sleep () с достаточной задержкой в ​​конце, чтобы проверить, происходит ли это, потому что поток, инициализирующий компонент, завершается. Однако это не помогло.

Как правильно сделать это внутри боба весной?

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();
        }


    }

`

1 Ответ

0 голосов
/ 16 октября 2019

Посмотрите на исходный код метода FirebaseReference.getReference():

public DatabaseReference getReference() {
  return new DatabaseReference(ensureRepo(), Path.getEmptyPath());
}

Он создает новый DatabaseReference каждый раз, когда вы вызываете его. То, как вы делаете это прямо сейчас, - вы добавляете ValueEventListener к DatabaseReference, который просто собирает мусор, поскольку вы каким-то образом не пропускаете его из этого метода.

Я предлагаю объявитьВаш DatabaseReference объект в виде компонента в классе @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;
  }
}

Теперь во всем приложении Spring необходимо автоматически подключать этот компонент DatabaseReference.

Еще более элегантным решением было быразделить ValueEventListener на его собственный компонент и автоматически связать его с методом DatabaseReference:

  @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;
  }

И в отдельном классе:

@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());
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...