I have a spring file config1.xml that has beans with no explicitly defined profile. I also have another file config2.xml with two bean profiles (profileA and profileB). If I import the latter one into the former and activate profileA at runtime, would the beans in config1.xml be activated? If not, is there a way to do this without replicating the code for config1.xml?
Yes, they will be activated. By default your beans have no profile and are loaded into the container. Only if you specify profiles for the beans explicitly, they will be bypassed unless one or more of the specified profiles are active.
Related
I'm new to spring and I'm studying it. And stumbled upon the #Profile annotation.
I want to write a simple project with Spring (not Springboot) to learn how to load properties based on the environment using #profile annotation. Almost everywhere, the examples (Ex1, Ex2) I see only with the Springboot. I'm wondering whether we cannot write a Spring application that can dynamically load the properties based on the environment (dev, prod).
Some examples ( Ex3, Ex4, Ex5) show with the #Profile but those have hardcoded the bean details for each environment like below. Is this how we have to write the property loading?
#Profile("dev")
#Bean
public String devDBCcnnection() {
System.out.println(dbConfiguration.getUrl());
return "DB Connection for Dev";
}
#Profile("test")
#Bean
public String devTestCcnnection() {
System.out.println(dbConfiguration.getDriverClassName());
return "DB Connection for Test";
}
#Profile("prod")
#Bean
public String devProdCcnnection() {
System.out.println("DB Connection for Prod");
return "DB Connection for Prod";
}
It has to write a bean for each profile like in the above example?
Can someone tell me using #Profiles, can't dynamically load the property values like in Spring applications?
Appreciate it if you can give the samples with Spring 5
Almost everywhere, the examples (Ex1, Ex2) I see only with the
Springboot. I'm wondering whether we cannot write a Spring application
that can dynamically load the properties based on the environment
(dev, prod).
Spring boot uses the spring context. The spring context allows you to use profiles. Therefore no problem using profiles with simple Spring project (non spring-boot).
There are many ways that you can use Profiles.
One of them is the example that you gave with specific beans that have #Profile and get registered in spring for a specific profile.
Another one, more commonly used in enteprise applications is to ship a jar application with multiple application.yaml files. So for example you ship your application, containing dev-application.yaml and qa-application.yaml. You can then start your application selecting a specific profile to be active. Then that specific application.yaml will be used when the application starts up to build the spring context. So the aplication will be started with qa-application.yaml and will have a connection to the QA database.
But be careful the default application.yaml will also be loaded. The specific application.yaml for example qa-application.yaml will be loaded on top of default application.yaml.
The following article contains very good information about spring profiles
spring profiles article
Considering my example here, I quotte something relevant from that article.
The Default Profile The default profile is always active. Spring Boot
loads all properties in application.yml into the default profile. We
could rename the configuration file to application-default.yml and it
would work the same.
Other profiles will always be evaluated on top of the default profile.
This means that if a property is defined in the default profile, but
not in the qa profile, the property value will be populated from the
default profile. This is very handy for defining default values that
are valid across all profiles.
In order to activate a specific profile
For non spring-boot projects here is a very good answer spring active profile
For spring-boot projects you can
Use a system variable to start your jar file
java -Dspring.profiles.active=qa -jar myApp.jar
Use an environment property to start your jar file
export SPRING_PROFILES_ACTIVE=qa
java -jar myApp.jar
At this moment we have monolith app where all mbeans are defined in single place.
In future they will be migrated and placed in dedicated modules, each module will have their spring context definition.
Found #EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING) useful for migration from original solution to a new approach. My spring version is 5.2.4
I wish to have control over mbeans export, but noticed from javadoc (AnnotationMBeanExporter) that by default using this annotation export ALL mbeans from spring context. It means that jmx configuration from module A will publish mbeans from other modules B or C, even mbeans from 3rd party libraries will be available.
I planned to set JMX configuration only on specific modules that would like to expose mbeans and not sure if:
have to change approach and place #EnableMBeanExport once, somewhere in main configuration
have to create a new annotation, that would change default process
add sth to annotation to activate it on specific module
See the javadocs for #EnableMBeanExport.
* <p>The resulting {#link org.springframework.jmx.export.MBeanExporter MBeanExporter}
* bean is defined under the name "mbeanExporter". Alternatively, consider defining a
* custom {#link AnnotationMBeanExporter} bean explicitly.
*
So simply declare the AnnotationMBeanExporter as a #Bean and configure it to only register the beans you need.
See Controlling the Registration Behavior.
Is it possible to have a profile in spring boot and also another profile that inherits most of the parent values and beans?
For example I have two profiles
staging and staging-task.
I want staging-task to inherit the database configuration of the staging profile however I want it to override the jpa configuration.
Is profile inheritance available to #Configuration beans.
Yes. Its possible to have spring profiles in spring boot.
For your problem, put your common database configuration in application.yml(default profile).
And you can override the other properties in application-stage.yml.
Spring will read the properties from application.yml and override from application-stage.yml when active profile is stage.
TL;DR
The active profiles will cause respective application-$profile.properties to be read (if they exist) in the order the active profiles are defined. Later read properties override earlier ones. That will give you the means to do smth. like an hierarchy.
Long Version
There is no such thing as profile-inheritance in spring but it can be mimicked as written in the answer by JRR.
For how it actually works read: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-profile-specific-properties.
I am trying to figure out how can I dynamically update/reload externalized configuration in a Spring Boot application without restarting the whole application.
Most of the advice involves reloading ApplicationContext after changing the externalized configuration, but that is equivalent to restarting the entire application, so this is not really all that useful.
Reading through SpringBoot reference documentation, I found a chapter 23.7 Typesafe Configuration Properties.
If I understand it correctly, this allows to define simple POJO classes that will hold your application (externalized) configuration values as attributes.
In theory at least, this scheme could be used to bind beans only once to the required configuration POJO and upon configuration change just update the values in the POJO. Components could easily pick up the changes next time they access getters on the POJO...
However, I have yet not managed to figure out how to enable this type of behavior. Is there some glaringly obvious way to dynamically update components annotated with #ConfigurationProperties when relevant configuration has changed?
It sounds like you're looking for #RefreshScope which is provided by Spring Cloud. From the Spring Cloud documentation:
A Spring #Bean that is marked as #RefreshScope will get special treatment when there is a configuration change. This addresses the problem of stateful beans that only get their configuration injected when they are initialized. For instance if a DataSource has open connections when the database URL is changed via the Environment, we probably want the holders of those connections to be able to complete what they are doing. Then the next time someone borrows a connection from the pool he gets one with the new URL.
Is there a way to update a Spring bean dynamically if the spring beans configuration changes?
E.g. assume that I have a spring bean with boolean property x and the spring beans has the value true when the application starts.
So spring creates the bean with the property x set to true.
Is there a way so that if I changes the property to x (while the application is running) that the property will be updated e.g. to false?
Calling the setter for x setX() method will do that.
But it should not be a prototype bean.
it is possible with the jrebel-spring integration. it monitors your configuration and TRIES to re-wire your beans at runtime.
Though i would not use it in production...only for playing around, testing etc
Spring reads configuration files at startup. If you really need to update configs while application running, you should manually implement all the chain: detecting config changes, validating config, detecting changed beans, updating beans in context.
Spring beans can be initialized using applicationContext.xml or even programatically. In your case; you will need to remove configurations from xml and add into java program. You can get some idea from How to programmatically create bean definition with injected properties? . Other good links were also available on google.