How to configure two instance mongodb use spring boot and spring data - java

The First instance is the embedded MongoDb, the second instance is the live MongoDb.
How do it configure use spring data and spring boot. How to switch easily these instances by properties file??
UPDATE
By default application should start build-in database and store data
into APPDIR/db directory
It should be possible to let application know that external database
will be used by configuring mongo.url property. In this case no need
to start internal database. Instead of that external connection
should be used
Paste some configuration, please.
UPDATE
I have:
<!--Embedded MongoDB-->
<dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
<version>1.50.5</version>
</dependency>
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.uri=mongodb://localhost/test
spring.data.mongodb.database=test
# EMBEDDED MONGODB (EmbeddedMongoProperties)
#spring.mongodb.embedded.storage.databaseDir=c:/db
#spring.mongodb.embedded.version=3.2.2
if I'll specify external mongodb, then i want embedded mongodb shouldn't to startup.
java.io.IOException: Could not start process: <EOF>
at de.flapdoodle.embed.mongo.AbstractMongoProcess.onAfterProcessStart(AbstractMongoProcess.java:79) ~[de.flapdoodle.embed.mongo-1.50.5.jar!/:?]
at de.flapdoodle.embed.process.runtime.AbstractProcess.<init>(AbstractProcess.java:114) [de.flapdoodle.embed.process-1.50.2.jar!/:?]
at de.flapdoodle.embed.mongo.AbstractMongoProcess.<init>(AbstractMongoProcess.java:53) [de.flapdoodle.embed.mongo-1.50.5.jar!/:?]
at de.flapdoodle.embed.mongo.MongodProcess.<init>(MongodProcess.java:50) [de.flapdoodle.embed.mongo-1.50.5.jar!/:?]
at de.flapdoodle.embed.mongo.MongodExecutable.start(MongodExecutable.java:44) [de.flapdoodle.embed.mongo-1.50.5.jar!/:?]
at de.flapdoodle.embed.mongo.MongodExecutable.start(MongodExecutable.java:34) [de.flapdoodle.embed.mongo-1.50.5.jar!/:?]
at de.flapdoodle.embed.process.runtime.Executable.start(Executable.java:101) [de.flapdoodle.embed.process-1.50.2.jar!/:?]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_05]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_05]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_05]
at java.lang.reflect.Method.invoke(Method.java:483) ~[?:1.8.0_05]

I think you can use Spring profiles.
Here's the documentation.
Spring Profiles provide a way to segregate parts of your application
configuration and make it only available in certain environments.
UPDATE
Note : Everything that I will talk about below is indicated in the documentation I mentioned above... You should really take a look to this documentation. This documentation is great (no joke).
From Appendix A. Common application properties (Spring boot documentation)
Here's how to configuration remote MongoDB instance in application.properties :
# MONGODB (MongoProperties)
spring.data.mongodb.authentication-database= # Authentication database name.
spring.data.mongodb.database=test # Database name.
spring.data.mongodb.field-naming-strategy= # Fully qualified name of the FieldNamingStrategy to use.
spring.data.mongodb.grid-fs-database= # GridFS database name.
spring.data.mongodb.host=localhost # Mongo server host.
spring.data.mongodb.password= # Login password of the mongo server.
spring.data.mongodb.port=27017 # Mongo server port.
spring.data.mongodb.repositories.enabled=true # Enable Mongo repositories.
spring.data.mongodb.uri=mongodb://localhost/test # Mongo database URI. When set, host and port are ignored.
spring.data.mongodb.username= # Login user of the mongo server.
And here's how to configure embedded MongoDB instance in application.properties:
# EMBEDDED MONGODB (EmbeddedMongoProperties)
spring.mongodb.embedded.features=SYNC_DELAY # Comma-separated list of features to enable.
spring.mongodb.embedded.storage.databaseDir= # Directory used for data storage.
spring.mongodb.embedded.storage.oplogSize= # Maximum size of the oplog in megabytes.
spring.mongodb.embedded.storage.replSetName= # Name of the replica set.
spring.mongodb.embedded.version=2.6.10 # Version of Mongo to use.
From Change configuration depending on the environment (Spring boot documentation)
To do the same thing with properties files you can use
application-${profile}.properties to specify profile-specific values.
You can define the MongoDB embedded configuration into application-dev.properties and the MongoDB remote configuration into application-prod.properties
UPDATE II : The return
I'm assuming that you start your embedded MongoDB instance in a class like (from documentation) :
import de.flapdoodle.embed.mongo.config.ArtifactStoreBuilder;
...
MongodStarter starter = MongodStarter.getDefaultInstance();
String bindIp = "localhost";
int port = 12345;
IMongodConfig mongodConfig = new MongodConfigBuilder()
.version(Version.Main.PRODUCTION)
.net(new Net(bindIp, port, Network.localhostIsIPv6()))
.build();
MongodExecutable mongodExecutable = null;
You can assign a spring profile to this class like (from documentation) :
#Configuration
#Profile("dev")
public class ProductionConfiguration {
// ...
}
This way, your embedded MongoDB is started only when you choose dev profile.

Related

Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured. Getting dis error while running app

This is application properties code,please check and tell me how to fix the error.
debug=true
server.port=9090
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect
#create, update, create-drop, validate
spring.jpa.hibernate.ddl-auto=update
#file related all configurations
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=10MB
project.image=images/
#here we are allowing debug so that we can get every log related to security on console
logging.level.org.springframework.security=DEBUG
#spring.profiles.active will tell us which profile we are using
spring.profiles.active= prod
This is application-developer properties code
spring.datasource.url=jdbc:mysql://localhost:3306/blog_app_apis
spring.datasource.username =
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.show-sql=true
This is application-production properties code
spring.datasource.url= jdbc:mysql://blog-db.cx8gwdujroiq.ap-south-1.rds.amazonaws.com:3306/blog_app_apis
spring.datasource.username = pankaj
spring.datasource.password=kicker12345
This is the error message:
APPLICATION FAILED TO START
Description:
Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
Reason: Failed to determine a suitable driver class
Action:
Consider the following:
If you want an embedded database (H2, HSQL or Derby), please put it on the classpath.
If you have database settings to be loaded from a particular profile you may need to activate it (the profiles prod are currently active).
Your production configuration is missing the database driver property, which you should clearly understand from the reason section in the exception message:
Reason: Failed to determine a suitable driver class
Since you have the application.properties file with the default configuration properties, you can use the fix suggested to you by the Spring framework:
Consider the following: If you want an embedded database (H2, HSQL, or Derby), please put it on the classpath. If you have database settings to be loaded from a particular profile you may need to activate it (the profiles prod are currently active).
In order to fix the error for the production profile you need to add the following property to your application.properties file: spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
The resulting file should look like this:
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.show-sql=true
debug=true
server.port=9090
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect
#create, update, create-drop, validate
spring.jpa.hibernate.ddl-auto=update
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=10MB
project.image=images/
#here we are allowing debug so that we can get every log related to security on console
logging.level.org.springframework.security=DEBUG
#spring.profiles.active will tell us which profile we are using
spring.profiles.active=prod
This will add the default database driver for all your profile. So be mindful to change this if some specific profile will use a database that differs from MySQL.
Updated:
You also have the incorrect name of the active profile. In your application.properties file you have a such line that sets the active profile of your application:
spring.profiles.active=prod
But your profile-based file is called application-production.properties. The Spring framework has a such naming format for configuration properties files:
application-[PROFILE_NAME].properties
So you should also rename your application-production.properties file to application-prod.properties to match the value from the spring.profiles.active property.

Dockerized Spring Application with environment variables

I am currently trying to run a Java Spring application in a Docker container. This has worked without any problems so far. But now I want that in the application.properties there are no fixed values but only placeholders, which are passed as environment variables to the container. According to the Spring Docs this should be possible but when I try this I always get the error that no database connection can be established to the placeholder ${DB_CONFIG} (Caused by: java.lang.RuntimeException: Driver com.mysql.cj.jdbc.Driver claims to not accept jdbcUrl, ${DB_CONFIG}).
I already tried to pass the application.properties externally, instead of an env file pass the variables directly as Docker environment variable and instead of a custom variable (DB_CONFIG) for the JDBC url pass the Spring variable (SPRING_DATASOURCE_URL). Neither variant worked for me.
I hope I got my point across correctly and you guys can help me out.
For your information: I don't maintain the source code, I just get it from a CI/CD, copy the changed application.properties to its place and compile the project.
KR,
BlackRose01
docker-compose file:
version: '3'
services:
arrowhead-serviceregistry:
container_name: arrowhead-serviceregistry
image: 'openjdk:11-jre-slim-buster'
restart: always
env_file: '.env'
ports:
- 8443:8443/tcp
volumes:
- ./arrowhead-serviceregistry-4.3.0.jar:/service.jar
depends_on:
- mysql
command:
-java -noverify -XX:TieredStopAtLevel=1 -jar /service.jar
application.properties file:
############################################
### APPLICATION PARAMETERS ###
############################################
# Database connection (mandatory)
# Change the server timezone if neccessary
spring.datasource.url=${DB_CONFIG}
spring.datasource.username=${SERVICEREGISTRY_DB_USERNAME}
spring.datasource.password=${SERVICEREGISTRY_DB_PASSWORD}
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
# use true only for debugging
spring.jpa.show-sql=false
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.hibernate.ddl-auto=none
# Service Registry web-server parameters
server.address=0.0.0.0
server.port=${SERVICEREGISTRY_PORT}
domain.name=${SERVICEREGISTRY_ADDRESS}
domain.port=${SERVICEREGISTRY_PORT}
############################################
### CUSTOM PARAMETERS ###
############################################
# Name of the core system
core_system_name=SERVICE_REGISTRY
# Show all request/response in debug log
log_all_request_and_response=${SERVICEREGISTRY_LOG_REQUESTS}
# Service Registry has an optional feature to ping service providers in a fixed time interval,
# and remove service offerings where the service provider was not available
# use this feature (true/false)
ping_scheduled=${SERVICEREGISTRY_PING_ENABLE}
# how much time the Service Registry should wait for the ping response (in milliseconds)
ping_timeout=${SERVICEREGISTRY_PING_TIMEOUT}
# how frequently should the ping happen, in minutes
ping_interval=${SERVICEREGISTRY_PING_INTERVAL}
# Service Registry has an optional feature to automatically remove service offerings, where the endOfValidity
# timestamp field is in the past, meaning the offering expired
# use this feature (true/false)
ttl_scheduled=${SERVICEREGISTRY_TTL_ENABLE}
# how frequently the database should be checked for expired services, in minutes
ttl_interval=${SERVICEREGISTRY_TTL_INTERVAL}
# Interface names has to follow this format <PROTOCOL>-<SECURITY>-<FORMAT>, where security can be SECURE or INSECURE and protocol and format must be a sequence of letters, numbers and underscore.
# A regexp checker will verify that. If this setting is set to true then the PROTOCOL and FORMAT must come from a predefined set.
use_strict_service_intf_name_verifier=${SERVICEREGISTRY_STRICT_INTERFACE_NAMES}
############################################
### SECURE MODE ###
############################################
# configure secure mode
# Set this to false to disable https mode
server.ssl.enabled=${SSL_ENABLED}
server.ssl.key-store-type=${SERVICEREGISTRY_SSL_KEYSTORE_TYPE}
server.ssl.key-store=${SERVICEREGISTRY_SSL_KEYSTORE}
server.ssl.key-store-password=${SERVICEREGISTRY_SSL_KEYSTORE_PASSWORD}
server.ssl.key-alias=${SERVICEREGISTRY_SSL_KEY_ALIAS}
server.ssl.key-password=${SERVICEREGISTRY_SSL_KEY_PASSWORD}
server.ssl.client-auth=${SERVICEREGISTRY_SSL_CLIENT_AUTH}
server.ssl.trust-store-type=${SERVICEREGISTRY_SSL_TRUSTSTORE_TYPE}
server.ssl.trust-store=${SERVICEREGISTRY_SSL_TRUSTSTORE_PATH}
server.ssl.trust-store-password=${SERVICEREGISTRY_SSL_TRUSTSTORE_PASSWORD}
#If true, http client does not check whether the hostname is match one of the server's SAN in its certificate
#Just for testing, DO NOT USE this feature in production environment
disable.hostname.verifier=${SERVICEREGISTRY_DISABLE_HOSTNAME_VERIFIER}
Environment file:
# Basic settings
DB_CONFIG=jdbc:mysql://127.0.0.1:3306/arrowhead?serverTimezone=Europe/Berlin
SSL_ENABLED=false
# Service Registry settings
SERVICEREGISTRY_ADDRESS=127.0.0.1
SERVICEREGISTRY_PORT=8443
SERVICEREGISTRY_DB_USERNAME=myUser
SERVICEREGISTRY_DB_PASSWORD=xxx
SERVICEREGISTRY_LOG_REQUESTS=false
SERVICEREGISTRY_PING_ENABLE=false
SERVICEREGISTRY_PING_TIMEOUT=5000
SERVICEREGISTRY_PING_INTERVAL=60
SERVICEREGISTRY_TTL_ENABLE=false
SERVICEREGISTRY_TTL_INTERVAL=10
SERVICEREGISTRY_STRICT_INTERFACE_NAMES=false
SERVICEREGISTRY_DISABLE_HOSTNAME_VERIFIER=false
SERVICEREGISTRY_SSL_KEYSTORE_TYPE=PKCS12
SERVICEREGISTRY_SSL_KEYSTORE=classpath:certificates/service_registry.p12
SERVICEREGISTRY_SSL_KEYSTORE_PASSWORD=123456
SERVICEREGISTRY_SSL_KEY_ALIAS=service_registry
SERVICEREGISTRY_SSL_KEY_PASSWORD=123456
SERVICEREGISTRY_SSL_CLIENT_AUTH=need
SERVICEREGISTRY_SSL_TRUSTSTORE_TYPE=PKCS12
SERVICEREGISTRY_SSL_TRUSTSTORE_PATH=classpath:certificates/truststore.p12
SERVICEREGISTRY_SSL_TRUSTSTORE_PASSWORD=123456
While searching for a solution to my problem, I came across the Spring Cloud Config Server (also just a Spring application that is self-hostable). This provides an interface between the configuration file storage location and the Spring application. The application is set up so that instead of a static application.(properties|yml) file, a bootstrap.yml is stored with the URL to the config server. When the application starts up, it then connects to the Config Server and receives it via a REST interface. The configuration files can be stored in Git/a DB or as a file.
Spring Docs - Cloud Config Server
Spring - Instruction for Implementation
Baeldung - Tutorial
Baeldung - Tutorial Bootstrapping

spring boot + docker + kubernetes

we have three environment as (dev, test and prod) and we have database configuration as below
spring:
jpa:
hibernate:
ddl-auto: update
datasource:
url: ${URL}
username: ${USERNAME}
password: ${PASSWORD}
What i am trying is that i create the jar and then build the image and when deploying in to the kubernetes , i will be using the dev , test and prod respective deployment.yaml in which i will be loading the url,username and password to env so the application will read it during prod start up
So when i am trying to build jar application try to connect to the database and it failed to create the jar.
Please let me know my understanding is wrong or right if wrong then how to correct it and just one thing is that i can't change the process i.e jar+ image + kubernetes
In Kubernetes you can put your configuration in Configmap or Secret. You can package the spring boot application and provide the Configmap entry as env variable of your container as exposed here
Using Spring Cloud Kubernetes you can also read these properties without any configuration on the container as explained in this article

Spring-boot, by database platform custom property

I want to have spring boot init-sql dynamic property by vendor or platform. Is this possible?
spring.datasource.tomcat.mysql-initSQL=mysql query
spring.datasource.tomcat.h2-initSQL=h2 query
I do know that is possible with other properties for example with flyway migrations:
flyway.locations=db/migration/{vendor}
or with sql initilization file
schema-${platform}.sql
You can do this using the Spring Profiles.
Create 2 profiles.
1) H2 2) MySQL
Create two init sql files in your class path schema-h2.sql, schema-mysql.sql
Add the spring.datasource.platform property to the profiles
In H2 Profile => "spring.datasource.platform = h2"
In MySQL Profile => "spring.datasource.platform = mysql"
This works as below.
When you application is started with h2 profile (spring.profile.active=h2) then the schema-h2.sql is picked for initialization.
When you application is started with mysql profile (spring.profile.active=h2) then the schema-mysql.sql is picked for initialization.

How to one-off run #DataJpaTest against real database instead of in-memory with Spring Boot

I am using Spring Boot 1.4.3 and have a whole bunch of tests that are annotated with #DataJpaTest. By default, they run against an in-memory database. I would like to be able to run all of them against a local MySQL temporarily. How can I do this in an easy way?
I have found that I can make it work for one by adding #ActiveProfiles("local") where I have an application-local.properties that points to my local MySQL, but it is just too much work to add that everywhere, run the tests and then remove it again (since I only want to run this manually against MySQL, the CI environment will run against the in memory db).
I am using Maven if that would matter.
UPDATE:
So I have an application-local.properties which contains the db properties to connect to my local MySQL database (Which I use already to run my application against the local MySQL)
Then I right-click in IntelliJ on a package and select "Run all tests in package". In the settings of that run configuration, I add -Dspring.profiles.active=local to the "VM options" field.
I would have thought that this would activate the local profile during the tests, but it does not. If I stop the local MySQL, the tests still run fine.
In the docs it states that you are able to remove the autoconfigured h2 datasource with #AutoConfigureTestDatabase(replace= Replace.NONE) on the test class https://docs.spring.io/spring-boot/docs/1.4.2.RELEASE/reference/html/boot-features-testing.html#boot-features-testing-spring-boot-applications-testing-autoconfigured-jpa-test.
Also you then need to provide your db setup in properties, so that it does not use your app properties e.g.:
# Database
spring.datasource.url=jdbc:mariadb://localhost:3303/test
spring.datasource.username=test
spring.datasource.password=test
spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
spring.jpa.hibernate.ddl-auto=none
spring.jpa.show-sql=true
i put this in application.properties in the test package
You can add the profile with the MySQL datasource properties in the same application.properties (or .yml) as:
application.yml
# Existing properties
---
spring:
profiles: h2
# More h2-related properties
---
spring:
profiles: postgres
database:
driverClassName: org.postgresql.Driver
datasource:
url: jdbc:postgresql://localhost:5432/db_dvdrental
username: user_dvdrental
password: changeit
jpa:
database: POSTGRESQL
generate-ddl: false
# More postgres-related properties
and either use #ActiveProfiles("postgres") in an integration test class or start teh container using VM argument as:
java -Dspring.profiles.active=h2 ...
Add application.yml(properties) with jdbc connection into src/test/resources
Run your JPA test with #AutoConfigureTestDatabase(replace= AutoConfigureTestDatabase.Replace.NONE) - it disables using embedded database (h2), otherwise :
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'dataSource': Invocation of init method
failed; nested exception is java.lang.IllegalStateException: Failed to
replace DataSource with an embedded database for tests. If you want an
embedded database please put a supported one on the classpath or tune
the replace attribute of #AutoConfigureTestDatabase.

Categories