无法使用 Spring Data Reactive 和 Spring Boot 2.0 连接到 mongoDB

5 ssl spring-data-mongodb project-reactor mongodb-atlas spring-webflux

每次尝试使用 Spring Data Reactive 和 Spring Boot 2.0 连接到 MongoDB 时,我都会收到以下错误。

Caused by: java.lang.UnsupportedOperationException: No SSL support in java.nio.channels.AsynchronousSocketChannel. For SSL support use com.mongodb.connection.netty.NettyStreamFactoryFactory
        at com.mongodb.connection.AsynchronousSocketChannelStreamFactory.<init>(AsynchronousSocketChannelStreamFactory.java:41)
        at com.mongodb.async.client.MongoClients.getStreamFactory(MongoClients.java:228)
        at com.mongodb.async.client.MongoClients.create(MongoClients.java:177)
        at com.mongodb.async.client.MongoClients.create(MongoClients.java:123)
        at com.mongodb.reactivestreams.client.MongoClients.create(MongoClients.java:103)
        at com.mongodb.reactivestreams.client.MongoClients.create(MongoClients.java:53)
        at org.springframework.boot.autoconfigure.mongo.ReactiveMongoClientFactory.createNetworkMongoClient(ReactiveMongoClientFactory.java:123)
        at org.springframework.boot.autoconfigure.mongo.ReactiveMongoClientFactory.createMongoClient(ReactiveMongoClientFactory.java:69)
        at org.springframework.boot.autoconfigure.mongo.ReactiveMongoAutoConfiguration.reactiveStreamsMongoClient(ReactiveMongoAutoConfiguration.java:67)
        at org.springframework.boot.autoconfigure.mongo.ReactiveMongoAutoConfiguration$$EnhancerBySpringCGLIB$$94536095.CGLIB$reactiveStreamsMongoClient$1(<generated>)
        at org.springframework.boot.autoconfigure.mongo.ReactiveMongoAutoConfiguration$$EnhancerBySpringCGLIB$$94536095$$FastClassBySpringCGLIB$$2171f816.invoke(<generated>)
        at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
        at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:358)
        at org.springframework.boot.autoconfigure.mongo.ReactiveMongoAutoConfiguration$$EnhancerBySpringCGLIB$$94536095.reactiveStreamsMongoClient(<generated>)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162)
        at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:587)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1246)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1093)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:534)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:491)
        at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:198)
        at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:250)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1128)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1056)
        at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:833)
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:740)
        at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:466)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1246)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1093)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:534)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:491)
        at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:198)
        at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:250)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1128)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1056)
        at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:833)
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:740)
        at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:466)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1246)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1093)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:534)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:491)
        at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:351)
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:108)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1604)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1349)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:574)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:491)
        at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:198)
        at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:250)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1128)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1056)
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:570)
        at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:358)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1337)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:574)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:491)
        at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:751)
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:865)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:541)
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:809)
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:404)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:347)
        at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:128)
        at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:98)
        at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116)
        at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:102)
        at org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener.prepareTestInstance(SpringBootDependencyInjectionTestExecutionListener.java:47)
        at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:243)
        at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:226)
        at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:288)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
        at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:290)
        at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:245)
        at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
        at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
        at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
        at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:189)
        at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:283)
        at org.apache.maven.surefire.junit4.JUnit4Provider.executeWithRerun(JUnit4Provider.java:173)
        at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:153)
        at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:128)
        at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:203)
        at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:155)
        at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:103)
Run Code Online (Sandbox Code Playgroud)

错误消息告诉我使用 NettyStreamFactoryFactory 来支持 SSL。有人有关于如何执行此操作的示例吗?我尝试连接的数据库是 MongoDB Atlas,它严格要求 SSL 连接。

下面是我的其余代码:

@SpringBootApplication
public class FlixMovieApiReactiveApplication {

    public static void main(String[] args) {
        SpringApplication.run(FlixMovieApiReactiveApplication.class, args);
    }

    // Add Data
    @Bean
    public CommandLineRunner initDatabase(MovieRepository repository) {

        // entire process blocking, done in beginning
        Flux<Movie> movieList = Flux.just(
                new Movie("movie1", "1", "movie1"),
                new Movie("movie2", "1", "movie2"),
                new Movie("movie3", "5", "movie3"),
                new Movie("movie4", "1", "movie4"),
                new Movie("movie5", "3", "movie5"),
                new Movie("movie6", "1", "movie6"),
                new Movie("movie7", "2", "movie7"),
                new Movie("movie8", "3", "movie8"),
                new Movie("movie9", "1", "movie9"),
                new Movie("movie10", "2", "movie10"),
                new Movie("movie11", "1", "movie11"),
                new Movie("movie12", "3", "movie12"),
                new Movie("movie13", "1", "movie13"),
                new Movie("movie14", "4", "movie14"),
                new Movie("movie15", "1", "movie15"),
                new Movie("movie16", "4", "movie16")
        );

        // delete then insert data.  blockLast(), allows something to subscribe to pipeline, block for last emitted element
        // data is written to the database.
        return args -> repository.deleteAll().thenMany(repository.save(movieList)).blockLast();
    }
}

@RestController
public class MovieRestController {

    @Autowired
    private MovieService movieService;

    @GetMapping(value = "/movies")
    public Flux<ResponseEntity<Movie>> list() {

        return movieService.list().map(m -> new ResponseEntity<>(m, HttpStatus.OK));
    }

    @GetMapping(value = "/moviesByRating")
    public Flux<ResponseEntity<Movie>> findByRating(
            @RequestParam(value = "rating", required = false) final String rating) {

        return movieService.findByRating(rating)
                .map(m -> new ResponseEntity<>(m, HttpStatus.OK));

    }

    @GetMapping("/movies/{movieId}")
    public Mono<ResponseEntity<Movie>> read(
            @PathVariable("movieId") final String movieId) {

        return movieService.read(movieId)
                .map(m -> new ResponseEntity<>(m, HttpStatus.OK))
                .defaultIfEmpty(new ResponseEntity<>(HttpStatus.NOT_FOUND));
    }

    @DeleteMapping("/movies/{movieId}")
    public Mono<ResponseEntity<Movie>> delete(
            @PathVariable("movieId") final String movieId) {

        return movieService.delete(movieId)
                .map(m -> new ResponseEntity<>(m, HttpStatus.OK))
                .defaultIfEmpty(new ResponseEntity<>(HttpStatus.NOT_FOUND));
    }

    @PutMapping("/movies/{movieId}")
    public Mono<ResponseEntity<Movie>> update(
            @PathVariable("movieId") final String movieId,
            @RequestBody final MovieRequest movieRequest) {

        return movieService.update(movieId, movieRequest)
                .map(m -> new ResponseEntity<>(m, HttpStatus.OK))
                .defaultIfEmpty(new ResponseEntity<>(HttpStatus.NOT_FOUND));

    }

    @PostMapping("/movies")
    public Mono<ResponseEntity<Movie>> create(
            @RequestBody final Mono<MovieRequest> movieRequest) {

        return movieService.create(movieRequest)
                .map(m -> new ResponseEntity<>(m, HttpStatus.OK))
                .defaultIfEmpty(new ResponseEntity<>(HttpStatus.NOT_FOUND));

    }

}

@Service
public class MovieServiceImpl implements MovieService {

    @Autowired
    private MovieRepository movieRepository;

    @Override
    public Flux<Movie> list(){
        return movieRepository.findAll();
    }

    @Override
    public Flux<Movie> findByRating(final String rating){
        return movieRepository.findByRating(rating);
    }

    @Override
    public Mono<Movie> update(String id, MovieRequest movieRequest) {

       return movieRepository.findOne(id).map(existingMovie -> {

           if(movieRequest.getDescription() != null){
               existingMovie.setDescription(movieRequest.getDescription());
           }
           if(movieRequest.getRating() != null){
               existingMovie.setRating(movieRequest.getRating());
           }
           if(movieRequest.getTitle() != null) {
               existingMovie.setTitle(movieRequest.getTitle());
           }

           return existingMovie;

       }).then(movieRepository::save);
    }

    @Override
    public Mono<Movie> create(Mono<MovieRequest> movieRequest) {

        return movieRequest.map(newMovie -> {

            Movie movie = new Movie();

            if(newMovie.getDescription() != null){
                movie.setDescription(newMovie.getDescription());
            }
            if(newMovie.getRating() != null){
                movie.setRating(newMovie.getRating());
            }
            if(newMovie.getTitle() != null) {
                movie.setTitle(newMovie.getTitle());
            }

            return movie;

        }).then(movieRepository::save);
    }

    @Override
    public Mono<Movie> read(String id) {
        return movieRepository.findOne(id);
    }

    @Override
    public Mono<Movie> delete(String id) {
        return movieRepository.findOne(id)
                .flatMap(oldValue -> movieRepository.delete(id).t