I am building a Spring Boot web application deployed to Tomcat which builds a DataSource bean using JNDI.
I have the following entry in application.properties to prevent a duplicate DataSource MBean from being created in JMX
# Prevent Spring from automatically exposing beans to JMX. Tomcat automatically creates an MBean when setting the
# JNDI data source, and an error gets thrown if spring then tries to add the data source MBean itself.
spring.jmx.enabled=false
But my question is this: there is a property called spring.datasource.jmx-enabled that is set to false by default. This seems like a fine grained setting that should disable only DataSource MBeans from being exposed by Spring, right? But that is not the case. Unless I disable all JMX, the DataSource MBean will be duplicated.
Related
is there any difference between debug=true and logging.level.root=debug , both are specified in application.properties file of spring boot application.
Below are references for both from spring boot documentation, unfortunately there they don't show any link between them but it looks like they serve same purpose.
https://docs.spring.io/spring-boot/docs/2.6.6/reference/htmlsingle/#features.logging.console-output
https://docs.spring.io/spring-boot/docs/2.6.6/reference/htmlsingle/#features.logging.log-levels
When you set debug=true a bunch of "core" loggers used under the hood by spring boot will be set to debug: web container (like a tomcat), spring boot itself, hibernate.
It won't affect the loggers of your application though - they'll still be at INFO severity level.
However, if you set something like logging.level.root=debug probably all the loggers will be set to DEBUG, so yes, technically there is a difference.
From the spring boot documentation:
When the debug mode is enabled, a selection of core loggers (embedded container, Hibernate, and Spring Boot) are configured to output more information. Enabling the debug mode does not configure your application to log all messages with DEBUG level.
I have a wildfly 10 (Java + Spring) project. I have a requirement to dynamically inject the datasource (mysql) config details to wildfly. But since wildfly depends on the standalone xml file at startup, and needs it before even the java beans are created, the only way I've found so far is to inject is by setting env vars (by running some other program/script to fetch the configs before wildfly starts). Is there any other better option?
Is it possible to do this through the same java application itself, ignoring the xml and set the right config? If yes, how?
DataSource object via JNDI
Externalize your JDBC connection details by using JNDI to access a naming/directory server to obtain an object implementing the DataSource interface.
With a DataSource object in hand, call getConnection to obtain a Connection.
See tutorial by Oracle, Connecting with DataSource Objects.
I am using Spring Cloud Embedding Config Server to get the configuration from Git while server startup. Its working fine. Below is my config.
bootstrap.properties
spring.application.name= "credentialInfo"
spring.cloud.config.server.bootstrap= "true"
spring.cloud.config.server.git.uri= "https://11111#bitbucket.global.company.com/scm/~11111/spring-cloud-config.git"
spring.cloud.config.server.git.username= "aaaa"
spring.cloud.config.server.git.password= "bbbb"
Now I have to get the properties from Git repo for each request with username and password collected from Customers.How can I achieve this ..?
Normally client application get properties from git though config server when startup and when call to "actuator/refresh" endpoint.
I'm that the requirement as you state its doesn't work well with Spring Boot.
When configurations are read (no matter from where, including the configuration service) they are used to configure spring beans during the startup.
For example, if you have a configuration of, say, db host, this configuration is supposed to be used by bean responsible for database connectivity (DataSource)
The point is that by the time that Application Context starts, beans are already configured.
Its true that some beans having refreashable scope define a custom logic to get "re-initialized" as a consequence of calling /refresh endpoint, but this is not what you're asking for (at least as far as I understood)
Instead you say, that the client does something during the application startup and this action should lead to beans change. This is potentially a very expensive operation and I don't think you should go in this direction. Usually beans are not re-created during runtime (of scope singleton, and the chances are that most of the beans are of this scope)
I have a small API running on PCF using Spring JPA. Of course, within the code, I could use a JDBC connection running prepared statements to access a bound MySQL instance. Doing this requires a username and password, as per normal standards when connecting to a database via Java.
However, with Spring JPA, I don't have to do any of this. I simply bind the MySQL instance and can perform my queries using the JPA API.
For lack of a better question, what is this magic?
Cloudfoundry with Spring Cloud follows 12-factor app patterns through out.
For configuration also it uses the config pattern suggested by 12-factor app patterns.
According to this pattern we should be storing properties outside the code in the environment as environment variables. So that application bundle can be deployed to any environment once it's built without any modifications. Since it picks up configuration from the environment variables, different environments have to define same environment variables with the different values.
Whenever you add a service to your application using cf bind-service Cloudfoundry sets predefined environment variables related to that service in the virtual machine (or container or whatever it has).
You can check these environment variables using cf env app-name.(Command Refeference)
Sample output of cf env app-name
{
"VCAP_APPLICATION": {
"application_id": "fa05c1a9-0fc1-4fbd-bae1-139850dec7a3",
"application_name": "my-app",
"application_uris": [
"my-app.10.244.0.34.xip.io"
],
"application_version": "fb8fbcc6-8d58-479e-bcc7-3b4ce5a7f0ca",
"limits": {
"disk": 1024,
"fds": 16384,
"mem": 256
},
"name": "my-app",
"space_id": "06450c72-4669-4dc6-8096-45f9777db68a",
"space_name": "my-space",
"uris": [
"my-app.10.244.0.34.xip.io"
],
"users": null,
"version": "fb8fbcc6-8d58-479e-bcc7-3b4ce5a7f0ca"
}
Using the spring actuator endpoints you can inspect all environment variables using /env endpoint. It lists more properties than cf env.
When spring detects that
cloud profile is active (set by spring.profiles.active environment property, or spring.profile property in spring cloud)
Auto Configuration is enabled (enabled by #SpringBootApplication)
No in memory Datasource dependency is present on the classpath (though I assume it would give cloud datasource configuration preference, even if in memory dependency were present)
No data source has been explicitly configured
Spring creates the Datasource bean itself using environment variables if a datasource service (like Postgres) has been bound to application.
Below is the link for the environment properties that it uses for creating Datasource.
https://docs.cloudfoundry.org/buildpacks/java/spring-service-bindings.html
Here is a list of Datasource only properties.
cloud.services.<database-service-name>.connection.hostname
cloud.services.<database-service-name>.connection.name
cloud.services.<database-service-name>.connection.password
cloud.services.<database-service-name>.connection.port
cloud.services.<database-service-name>.connection.username
cloud.services.<database-service-name>.plan
cloud.services.<database-service-name>.type
database-service-name is defined in the Manifest.yml file in the env: block
In my experience if there's only one database service added to the application, there was no need to define the database service name in the environment variables section.
Note: By default spring would try to use the servlet container's poolable connection support, however most of the time we our self have to configure some properties that are only supported by connection pool providers like Apache DBCP. In these cases we have to create Datasource bean manually using environment properties (using System.getProperty() or spring Environment.getProperty()).
When I try the following lookup in my code:
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
return (DataSource) envCtx.lookup("jdbc/mydb");
I get the following exception:
java.sql.SQLException: QueryResults: Unable to initialize naming context:
Name java:comp is not bound in this Context at
com.onsitemanager.database.ThreadLocalConnection.getConnection
(ThreadLocalConnection.java:130) at
...
I installed embedded JBoss following the JBoss wiki instructions. And I configured Tomcat using the "Scanning every WAR by default" deployment as specified in the configuration wiki page.
Quoting the config page:
JNDI
Embedded JBoss components like connection pooling, EJB, JPA, and transactions make
extensive use of JNDI to publish services. Embedded JBoss overrides Tomcat's JNDI
implementation by layering itself on top of Tomcat's JNDI instantiation. There are a few > reasons for this:
To avoid having to declare each and every one of these services within server.xml
To allow seemeless integration of the java:comp namespace between web apps and
EJBs.
Tomcat's JNDI implementation has a few critical bugs in it that hamper some JBoss
components ability to work
We want to provide the option for you of remoting EJBs and other services that can > be remotely looked up
Anyone have any thoughts on how I can configure the JBoss naming service which according to the above quote is overriding Tomcat's JNDI implementation so that I can do a lookup on java:comp/env?
FYI - My environment Tomcat 5.5.9, Seam 2.0.2sp, Embedded JBoss (Beta 3),
Note: I do have a -ds.xml file for my database connection properly setup and accessible on the class path per the instructions.
Also note: I have posted this question in embedded Jboss forum and seam user forum.
Thanks for the response toolkit.... yes, I can access my datasource by going directly to java:jdbc/mydb, but I'm using an existing code base that connects via the ENC. Here's some interesting info that I've found out ....
The above code works with JBoss 4.2.2.GA and here's the JNDI ctx parameters being used:
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces:
org.jboss.naming:org.jnp.interfaces
The above code works with Tomcat 5.5.x and here's the JNDI ctx parameters being used:
java.naming.factory.initial=org.apache.naming.java.javaURLContextFactory
java.naming.factory.url.pkgs=org.apache.naming
The above code fails with Embedded JBoss (Beta 3) in Tomcat 5.5.x with the above error message.
java.naming.factory.initial=org.apache.naming.java.javaURLContextFactory
java.naming.factory.url.pkgs=org.apache.namingThe above code fails with the above error using JBoss Embedded in tomcat 5.5.x
Anyone have any thoughts I what I need to do with configuring embedded JBoss JNDI configuration?
java:comp/env is known as the Enterprise Naming Context (ENC) and is not globally visible. See here for more information. You will need to locate the global JNDI name which your datasource is regsitered at.
The easiest way to do this is to navigate to JBoss' web-based JMX console and look for a 'JNDIView' (not exactly sure of the name - currently at home) mbean. This mbean should have a list method which you can invoke, which will display the context path for all of the JNDI-bound objects.
I had some similar issue with Jboss Embedded and i finally fix playing in the file:
test-Datasource-ds.xml
adding
<mbean code="org.jboss.naming.NamingAlias" name="jboss.jmx:alias=testDatasource">
<attribute name="FromName">jdbc/Example DataSource</attribute>
<attribute name="ToName">java:/testDatasource</attribute>
</mbean>
The problem was jboss add the prefix java:/ for all data source declared. So finally i had a datasource named testDatasource, overrided with that directive to jdbc/Example DataSource
Hope it works