2

Using the Mongobee for Migration with spring mongo

 plugins {
    id 'org.springframework.boot' version '2.3.1.RELEASE'
    id 'io.spring.dependency-management' version '1.0.9.RELEASE'
    id 'java'
}

group = 'fete.bird'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '14'
compileJava {
    options.compilerArgs += ["--enable-preview"]
}
repositories {
    mavenCentral()
}
ext {
    set('springCloudVersion', "Hoxton.SR6")
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter'
    testImplementation('org.springframework.boot:spring-boot-starter-test') {
        exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
    }
    implementation 'org.springdoc:springdoc-openapi-ui:1.4.3'
    implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    implementation 'org.springframework.cloud:spring-cloud-starter-config'
    implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'

    compile 'com.github.mongobee:mongobee:0.13'
}
dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
    }
}

test {
    useJUnitPlatform()
}

Doing the constructor dependency for MongoTemplate causing the error org.springframework.beans.factory.UnsatisfiedDependencyException:Error creating bean with name 'mongoTemplate'

Here is the configuration code

@Configuration
public class ProductMigration {
    private final Environment environment;
    private MongoTemplate mongoTemplate;
    private static final Logger logger = LoggerFactory.getLogger(FeteBirdProductApplication.class);

    public ProductMigration(Environment environment, MongoTemplate mongoTemplate) {
        this.environment = environment;
        this.mongoTemplate = mongoTemplate;
    }

    @Bean
    public Mongobee mongobee(){
        logger.info("Starting product migration ...");
        String mongoUri = environment.getProperty("spring.data.mongodb.uri");
        boolean migrationsEnabled = Boolean.parseBoolean(environment.getProperty("app.db.migrations.enabled"));
        Mongobee runner = new Mongobee(mongoUri);
        runner.setEnabled(migrationsEnabled);
        runner.setChangeLogsScanPackage("fete.bird.fetebirdproduct.migration");
        runner.setChangelogCollectionName("migrations");
        runner.setLockCollectionName("migrations_lock");
        runner.setMongoTemplate(this.mongoTemplate);
        logger.info("Product migration completed...");
        return runner;
    }
}

The issue is caused by constructor dependency for MongoTemplate, but don't know how to solve the issue,

I tried @Autowired, didn't work same issue.

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'mongoTemplate' defined in class path resource [org/springframework/boot/autoconfigure/data/mongo/MongoDatabaseFactoryDependentConfiguration.class]: Unsatisfied dependency expressed through method 'mongoTemplate' parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'mongoDatabaseFactory' defined in class path resource [org/springframework/boot/autoconfigure/data/mongo/MongoDatabaseFactoryConfiguration.class]: Unsatisfied dependency expressed through method 'mongoDatabaseFactory' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mongo' defined in class path resource [org/springframework/boot/autoconfigure/mongo/MongoAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.mongodb.client.MongoClient]: Factory method 'mongo' threw exception; nested exception is java.lang.NoSuchFieldError: UNSPECIFIED
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:797) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:538) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1338) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:226) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1304) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1224) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:640) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    ... 25 common frames omitted
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'mongoDatabaseFactory' defined in class path resource [org/springframework/boot/autoconfigure/data/mongo/MongoDatabaseFactoryConfiguration.class]: Unsatisfied dependency expressed through method 'mongoDatabaseFactory' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mongo' defined in class path resource [org/springframework/boot/autoconfigure/mongo/MongoAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.mongodb.client.MongoClient]: Factory method 'mongo' threw exception; nested exception is java.lang.NoSuchFieldError: UNSPECIFIED
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:797) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:538) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1338) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:226) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1304) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1224) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:884) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:788) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    ... 38 common frames omitted
4

4 回答 4

1

The version of Spring Data MongoDB included in Spring Boot 2.3 uses version 4 of Mongo's Driver, but Mongobee depends on version 3. The two versions have different Maven coordinates (group ID and artifact ID) so you end up with both of them on the classpath. This leads to some code from version 4 of the driver using code from version 3 and a NoSuchFieldError results.

You can avoid the problem by excluding the Mongo Driver from the Mongobee dependency:

compile('com.github.mongobee:mongobee:0.13') {
    exclude group: 'org.mongodb'
}
于 2020-07-14T13:15:22.157 回答
0

It seems you don't have the bean created for "MongoTemplate"

Create a bean for it and use that to setMongoTemplate for Mongobee.

Below is the example to do so

@Bean
public MongoClient mongo() {
    return new MongoClient("localhost");
}

@Bean
public MongoTemplate mongoTemplate() throws Exception {
   return new MongoTemplate(mongo(), "test");
}

then use this

@Bean
public Mongobee mongobee(){
    logger.info("Starting product migration ...");
    String mongoUri = environment.getProperty("spring.data.mongodb.uri");
    boolean migrationsEnabled = Boolean.parseBoolean(environment.getProperty("app.db.migrations.enabled"));
    Mongobee runner = new Mongobee(mongoUri);
    runner.setEnabled(migrationsEnabled);
    runner.setChangeLogsScanPackage("fete.bird.fetebirdproduct.migration");
    runner.setChangelogCollectionName("migrations");
    runner.setLockCollectionName("migrations_lock");
    runner.setMongoTemplate(mongoTemplate());
    logger.info("Product migration completed...");
    return runner;
}

Now, you don't have to use constructor dependency and later wherever you want MongoTemplate you can use

 @Autowired  
 MongoTemplate mongoTemplate;

Hope, this will solve your problem !!

于 2020-07-14T11:10:42.750 回答
0

You are running across an incompatibility between the MongoDB Java driver required by the newer versions of Spring Data MongoDB, and the one used by mongobee. Spring Data MongoDB requires version 4 of the Mongo Java libraries, whereas mongobee requires version 3. The two versions are incompatible with each other, and cannot be used concurrently within an application.

By all indications, mongobee has been abandoned by its creators, with the last commit being made in March, 2018, and no responses to issues by the creators since then. Therefore, don't expect an updated version of that library to be released with support for the new version of the Mongo Java drivers.

Due to this project abandonment, several successor libraries were forked from mongobee. From what I have been able to determine, Mongock is the only remaining actively maintained successor library. It has support for both version 3 and version 4 of the Mongo Java libraries.

Mongock is a significant evolution of Mongobee, with built-in support for migrating from mongobee. In addition to its built-in support for version 4 of the Mongo Java driver, it has optional built-in integration with Spring & Spring Boot.

Therefore, if you wish to use a recent version of Spring Data MongoDB with a mongobee-compatible migration library, Mongock is going to the be easiest, most straightforward approach.

dependencies {
    [...]

    compile 'com.github.cloudyrock.mongock:mongock-api:4.1.14'
}
于 2020-08-10T22:31:19.960 回答
-1

Here it is,

@Bean
public MongoClient mongo() {
    return new MongoClient("localhost");
}
于 2020-07-14T13:14:38.980 回答