Saya memiliki proyek boot Spring modul multi-Maven yang memiliki struktur berikut:

parent
   |_ pom.xml
   |_ webservices
        |_ src/main/java
             |_ webservices
                  |_ WebServicesConfig.java
                  |_ WebServicesStarter.java
                  |_ GlobalPropertiesLoader.java
        |_ pom.xml
   |_ backend
        |_ src/main/java
             |_ backend
                  |_ BackendStarter.java
        |_ pom.xml
   |_ commons
        |_ src/main/java
             |_ commons
                  |_ GlobalPropertiesDAO.java
                  |_ GlobalPropertiesRepository.java
                  |_ CommonsConfig.java;
        |_ pom.xml

Kedua layanan web, dan backend adalah aplikasi boot Spring individu (mereka menghasilkan file jar yang saya gunakan untuk meluncurkannya) dan mereka bergantung pada modul commons. Jadi saya telah memasukkan commons sebagai ketergantungan pada layanan web dan pom.xml backend.

Saya memiliki beberapa pertanyaan tentang memulai aplikasi saya.

  1. Bagaimana cara memulai backend dan layanan web dalam satu JVM? (Di pelabuhan yang sama)
  2. Saya ingin melakukan auto-wire GlobalPropertiesRepository (terletak di dalam proyek bersama) di proyek backend dan layanan web saya. Bagaimana cara melakukannya? Bisakah saya melakukan auto-wire di berbagai modul? Mengimpor milik bersama saja tidak akan berhasil. Itu melempar "tidak ada kesalahan definisi kacang". Saya pikir ini karena GlobalPropertiesRepository tidak diluncurkan oleh wadah Spring jika saya mengimpornya.

============== PEMBARUAN =============

Menambahkan kelas Konfigurasi saya untuk aplikasi:

Aplikasi commons memiliki kelas Konfigurasi kosong untuk saat ini karena saya hanya memiliki kelas Repositori saya di sana. Di bawah ini adalah kelas Konfigurasi yang kosong:

package commons;

import org.springframework.context.annotation.Configuration;

@Configuration
public class CommonsConfig {

}

Dan ini adalah GlobalPropertiesRepository:

package commons;

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface GlobalPropertiesRepository extends CrudRepository<GlobalPropertiesDAO, Long>{
}

Di bawah ini adalah kelas-kelas yang diperlukan dalam aplikasi webservices:

Kelas pemula:

package webservices;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;

@SpringBootApplication
@EnableJpaRepositories
@ComponentScan({"commons", "webservices"})
public class WebServicesStarter {

    public static void main(String[] args) throws Exception {
        SpringApplication.run(WebServicesStarter.class, args);

        ClassPathScanningCandidateComponentProvider provider =
                new ClassPathScanningCandidateComponentProvider(true);
    }

}

Kelas Konfigurasi:

package webservices;


import org.springframework.boot.context.embedded.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

import commons.CommonsConfig;

@Configuration
@Import(CommonsConfig.class)
public class WebServicesConfig {

    @Autowired CommonsConfig commonsConfig;
    public WebServicesConfig() {
    }
}

Dan kelas tempat saya mencoba melakukan autowire repositori:

package webservices;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import commons.GlobalPropertiesDAO;
import commons.GlobalPropertiesRepository;

@Component
@Scope("singleton")
public class GlobalPropertiesLoader {

    @Autowired
    public GlobalPropertiesRepository globalPropertiesRepository;

    private GlobalPropertiesDAO globalProperties;

    @PostConstruct
    public void init(){
        globalProperties = globalPropertiesRepository.findOne(1L);
    }

    public GlobalPropertiesDAO getGlobalProperties(){
        return globalProperties;
    }

}

Ini adalah kesalahan yang saya dapatkan:

Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: public commons.GlobalPropertiesRepository webservices.GlobalPropertiesLoader.globalPropertiesRepository; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [commons.GlobalPropertiesRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:561)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331)

Terima kasih.

1
drunkenfist 14 Mei 2015, 20:46
Jika Anda telah menyertakan modul commons sebagai dependensi pakar dalam modul layanan web, maka Anda tidak perlu menjalankan kedua modul tersebut. Modul layanan web akan memiliki akses ke ketergantungan umum. Jika Anda ingin mengotomatiskan repositori, pertama-tama Anda perlu mengimpor kelas konfigurasi dari modul umum. Lihat [ini] (docs.spring .io/spring-javaconfig/docs/1.0.0.M4/reference/html/…) misalnya
 – 
jrao77
14 Mei 2015, 21:37
Terima kasih. Tetapi saya perlu meluncurkan dua aplikasi terpisah. Saya telah menyederhanakan pertanyaan saya sebelumnya. Saya telah mengedit pertanyaan saya sekarang.
 – 
drunkenfist
14 Mei 2015, 21:52
Saya tidak yakin apakah itu bisa dilakukan. Anda dapat mencoba mengemasnya sebagai Perang (Boot musim semi memiliki dukungan untuk ini) dan memasukkan keduanya ke dalam wadah yang sama? Lihat ini misalnya docs.spring.io/spring-boot/docs/current/reference/htmlsingle/…
 – 
jrao77
15 Mei 2015, 12:40
Oke, saya akan mencobanya. Tetapi saya masih tidak dapat mengotomatiskan repositori untuk aplikasi lain. Saya mencoba @importing kelas Konfigurasi dari aplikasi lain, tetapi saya belum mendeklarasikan repositori di kelas Konfigurasi. Jadi saya tidak berpikir itu adalah cara untuk pergi. Pertanyaan saya mirip dengan ini: stackoverflow.com/questions/22442822/…. Saya telah melakukan apa pun yang disarankan dalam pertanyaan itu, tetapi masih tidak berhasil.
 – 
drunkenfist
16 Mei 2015, 21:57
Bisakah Anda membagikan kelas @Configuration Anda untuk penyiapan repositori dan modul backend tempat Anda menghubungkannya dan konfigurasinya?
 – 
jrao77
16 Mei 2015, 22:56

1 menjawab

Jawaban Terbaik

Saya pikir saya tahu apa yang menyebabkan kesalahan.

Di kelas pemula aplikasi Anda meskipun Anda memiliki @ComponentScan({"commons", "webservices"}) untuk beberapa alasan kacang @Repository diabaikan. Saya pikir masalahnya ada di kelas ClassPathBeanDefinitionScanner. Menurut dokumentasi JavaDoc, ini menyatakan bahwa secara default akan memindai semua komponen, termasuk @Repository. Tetapi ketika mengidentifikasi antarmuka repositori, pemeriksaan lain gagal dalam metode isCandidateComponent. (jika Anda melihat di sumbernya)

Jadi kami mendapatkan log ini saat Anda mengaktifkan debug

18-05-2015 11:10:13.399 DEBUG 67917 --- [ main] oscaClassPathBeanDefinitionScanner : Diabaikan karena bukan kelas tingkat atas yang konkret: file [****/jpa-test/dl /target/classes/commons/GlobalPropertiesRepository.class]

Lebih lanjut, karena EnableJpaRepositories hanya memindai paket yang dideklarasikannya , repositori tidak sedang diinisialisasi.

Jika Anda menyetel properti baseClassPackage (type safe) seperti @EnableJpaRepositories(basePackageClasses = GlobalPropertiesRepository.class) maka repositori akan diinisialisasi. Pastikan juga Anda menambahkan @EntityScan(basePackageClasses = GlobalPropertiesDAO.class)

1
jrao77 18 Mei 2015, 15:17
Wah thx banget. Ini bekerja. Saya tidak pernah tahu kami memiliki basePackages dengan '@EnableJPARepositories'. Saya menggunakan basePackages alih-alih basePackageClasses. Juga, mengapa saya perlu menambahkan @EntityScan ? Tampaknya bekerja tanpa itu.
 – 
drunkenfist
19 Mei 2015, 00:40
Adalah untuk memindai entitas JPA. Ketika saya menguji, ia mengeluh bahwa GlobalPropertiesDAO (yang saya buat sebagai Entitas) tidak dikelola. Jadi saya pikir Anda bisa mengalami masalah serupa. ya basePackages juga berfungsi, tetapi ini adalah nilai string dan mudah untuk salah :)
 – 
jrao77
19 Mei 2015, 00:52