Applying settings in Spring based application in runtime - spring

We have Spring based (Spring.NET) web application and use VariablePlaceholderConfigurer to keep some settings in a separate properties file.
These properties are mainly different values affecting business logic, like emails, timeouts, paths, etc.
Now we need to implement administrative UI to allow users to change these settings in more friendly way.
So we will move all these settings to a database.
Question: What is the best (standard, common) approach to implementing settings like I described in Spring based application? (Assuming we want changes to be effective immediately without application restart.)
It is good if we can keep our current approach when setting values as just properties of beans.

The VariablePlaceholderConfigurer is ObjectFactoryPostProcessor, which is only invoked after reading the object definitions. So you cannot simply introduce a new IVariableSource that you refer to in your VariablePlaceholderConfigurer configuration, because it will only take effect after container reload.
You have to create an IObjectObjectPostProcessor to modify properties on container managed objects at runtime.

Related

What are the consequences of checking "Disable Auto Config Detection" in the Eclipse Spring preferences?

I mean the Eclipse preference under Window|Preferences|Spring|Beans Support
"Disable Auto Config Detection".
When this option is not checked, I notice a delay when saving Java files:
Building Workspace...
Loading ...ServerApplication
or
Loading ...DaoConfig
These messages are for Spring Boot main application classes (ServerApplication) or Spring configuration classes with #ComponentScan (DaoConfig) which are located in the workspace.
This can take a few seconds, which is a bit annoying.
When I check the above preference option, I don't notice the delay for loading these classes (at least for the Spring Boot main classes).
What are the consequences of disabling Auto Config Detection, e.g. what does this option really do, what functionality do I loose? Any pointers to documentation?
Can I speed up the save process without having to disable Auto Config Detection?
In STS3, the IDE creates an internal model of your Spring application, so that it can display a nice overview of your Spring elements in the Spring Explorer view, provide content-assist in Spring XML config files and more. In order to build up this internal Spring beans model, it needs to know where to start from when building that model. You can define those entry points manually in the properties for each project: Spring -> Beans Support. That preference allows you to define Spring XML config files and/or Spring-annotated configuration classes to be used by the IDE internally to build up that model.
In addition to that there is a mechanism to detect those files (Spring XML config files and Spring Boot application configuration annotations) automatically, so that you don't need to configure them manually. But the result is the same. Those files/classes end up being configured to be used by the IDE to built this internal model.
I guess that the delay that you see comes from building this internal beans model - this is at least what the messages indicate that you mentioned.
So far for the background. You can disable that auto-config mechanism and you don't need to configure those files/classes manually. This will result in the Spring Explorer, for example, not showing anything meaningful for those projects.
As an alternative and in case you are working mostly with Spring Boot projects, I would strongly recommend to switch to the all-new Spring Tools 4 (also available as a ready-to-use Eclipse distribution). It provides a slightly different set of features and is implemented in a different way, so that it doesn't need the expensive internal bean model creation. You should give it a try. And if you are missing something that you love in STS3 that is not yet part of Spring Tools 4, let us know.

How to load beans based on custom properties

I have custom implementation of PropertySourcesPlaceholderConfigurer, which I'm using to load additional property sources and placing them into different position (one on the end, and one before systemProperties). So properties can be overridden on different level.
Based on some properties, I need to load set of beans. For that I'm implementing ImportBeanDefinitionRegistrar.
Unfortunately that ImportBeanDefinitionRegistrar is executed before PropertySourcesPlaceholderConfigurer.
I also tried to use #ConditionalOnProperty, with the same result. And with PropertySourceFactory which is executed on the early beginning, but at that point I can't position those additional property sources.
Is there a way to add additional PropertySource in custom order before ImportBeanDefinitionRegistrar, or on the early beginning of Spring lifecycle?
Here I have sandbox app to play with the concept.
In reality I have this as in house library for Spring and Spring Boot applications, to enable additional functionalities with properties.
You should implement EnvironmentPostProcessor and move all the logic for the property sources there. You current project is broken in the sense that you have no guarantee that #PropertySource is going to be processed early (actually, it won't).

How do I manage name spaces in a Spring Integration project with multiple flows

I have a Spring Integration project that has several flows (some where between 10-15). I would like to keep my namespace clean since several flows might have similar sounding components (for ex - several flows might have a channel named fileValidatorChannel). I think I have a couple of different options to keep names from colliding with each other:
A. Preface every component name with the flow that it belongs to. For ex - flowAFileValidatorChannel, flowBFileValidatorChannel, etc
B. Create a context hierarchy where every flow is it's own context and every flow inheriting from a master context where all the common beans/sub-flows are.
What's the better approach? Is there are better way to keep my name space clean?
To be honest your problem isn't clear.
Any Spring Integration component is a bean finally. So, their ids are just to distinguish them from other bean.
Let's imaging if you don't have Spring Integration in your application. So, you would worry about some clean naming strategy for all your beans anyway?
From other side consider to use Spring Integration Flow project:
The goal is to support these, and potentially other semantics while providing better encapsulation and configuration options. Configuration is provided via properties and or referenced bean definitions. Each flow is initialized in a child application context. This allows you to configure multiple instances of the same flow differently.

Spring Environment profiles and server properties

I have a requirement to load properties for different environments like DEV, QA and I have different properties file for each environment. So I solved this by setting environment property in server and accessing this value to load respective property files. When googled I found that Spring Environment Profiles provides the solution for similar scenarios. However, even here I have to set active-profile variable in server as environment variable.
What are the benefits of using Spring Environment Profiles over my native approach?
Profile lets you override anything in the Spring Context, properties, beans etc, from environment to environment, customer to customer. It is a easy and clean way to have custom implementations at any level of your beans.
For example, Lets assume your are building a product which read data from a relational database, you can develop DAO layer with profile="default". Then if another customer of yours or you yourself want to provide NoSQL support, you can develop another DAO layer with profile="nosql". This will make sure you can same product on both support based on profile. Easy and clean.
I am working on a project which have profile="local" which will help you bring application locally with out any database dependency (kind of mock mode). You can think of million other applications like to make use of Profile concept.

OSGi and Component Management

I have a dynamic application that uses OSGi to load modular functionality at runtime. OSGi bundles contain the modular functionality and the application loads the bundles when they are needed. This approach works okay, but I would like a more granular solution. The bundles contain components controlled through Declarative Services. I'd like to be able to load a bundle, and only enable the components that are needed within the bundle. I've done research in this area, but cannot find a solution that I'm satisfied with. One approach was to create a "gatekeeper" component that is always enabled in the bundle and through the ComponentContext let it call enable and disable component. It's a viable solution, but I could not figure out a way for the "gatekeeper" to "know about" the other components in the bundle without hard coding the component names as properties in the "gatekeepers" SCR xml descriptor.
What I prefer is a way to load bundles and "know about" all components within the loaded bundles. Be able to determine what bundle the components are located in and what state they are currently in (similar to the equinox console command 'ls' that lists out all components). I would like to enable and disable the components when needed.
How does the console do this and how could I do this in an application?
Update:
#Neil Bartlett: Sorry for the delay. I had to move on to something else. Now I'm back on this issue. Really would appreciate any further assistance. My application is role based. I need to enable components based on the functionality they provide. The goal is for all role based components to initially be disabled. Upon role change, a role manager polls each component for its provided functionality and determines whether to load it. Each component will broadcast what functionality it provides (through a common service interface). ScrService will not allow me to enable an initially disabled service component. Having the components initially enabled and let ScrService disable them as soon as possible during application startup does not fit my needs.
Have a look at ScrService. Bothe equinox and felix has it.
However, components can be made to load lazily, i.e. only when needed by other components/bundles; but that is perhaps not what you want.
In your service description, mark the components as enabled, but requiring configuration information provided by the Configuration Management service. you then can write a CM plugin service (can't remember the exact term) that can publish and modify the configuration of your components. Services by default are identified by their name, which by default is their implementation class name. Configuration data is passed as a map, and it can be empty. DS will make the service available as soon as the CM provides a configuration.
I have a similar issue, but for a different purpose:
- I have apache file install and configuration admin service to configure my components externally with property files.
- I needed to make sure that some components get the config from the outer file and the only way I've found so far is that I mark my components with ConfigurationPolicy.REQUIRED.
- But that way my plugin projects doesn't run in eclipse (where there are no config files).
- The component.xml also contains a default development configuration so I'm okay with that, just my component doesn't start until there is a config data avalilable with configadmin. My components ar unsatisfied this way, until someone creates a configadmin entry.
- I figured out that if I create a osgi command line extender that sends empty configurations to service pid's they would start up with default values in component.xml files.
- I just came here to find a way to list all bundles
But I think this solution I use can also work with your setup and that's why I write this.
Just mark all your components with the configurtationpolicy.require and you can selectively start and stop them with adding and removing configurations with configadmin. This could be hard if you already use the configadmin for other purposes too, but it may be managable as a last resort.

Resources