nI am developing a Spring MVC web app using Spring 3.2. We will deploy the web app to different customers. Each customer may use one of several implementations of a service interface.
It's possible that the customer may need to reset these values, so we can't just hard-wire the implementation into the application, it needs to be externally configurable.
We are already using customer-specific property files that for setting simple properties such as Strings, numbers etc, but I'm asking how to set a particular implementation of an interface.
E.g.,
class MyClass {
// this is straightforward
#Value("${customer.propertyInPropertyFile}")
private String customerSpecificString;
// how to set the correct implementation for each customer?
private ISomeService service;
}
If there are 4 implementations of ISomeService, we can't autowire, or explicitly set a bean, as this will then be set in the compiled code - and it needs to be configurable after the application is deployed ( it would be OK to restart the application though if need be)..
Does anyone know how to do this? Would this better be performed using Spring EL, or profiles?
Thanks!
So, as I wanted to used Java configuration, I used the following solution:
#Configuration
#Profile("prod")
#EnableAsync
public class ProductionConfig extends BaseConfig
// inject property value which identifies theimplementation to use
Value("${service.impl}")
private String serviceName;
#Bean()
public IRepository repository() {
IRepository rc = null;
if(StringUtils.isEmpty(serviceName)){
rc = new Impl1();
} else if ("sword-mets".equals(serviceName)){
rc = new Impl2();
} else {
rc = new Impl3();
}
log.info("Setting in repository implementation " + rc);
return rc;
}
So, this isn't quite as clean as the suggested reply using aliases - the Config class needs to know about all the possible implementation classes - but is simple and avoids having to use the XML config just for this bean.
Related
TLDR: I need an interface/abstract class and all classes implementing it to have access to a Spring managed bean. Can Spring inject a bean into an interface/abstract-class and its subclasses simply via #Autowired ?
I am working on an API built with Spring Webflux + Cloud Gateway that depending on the cookie JWT authorized party, identifies the User's policy group and assign an Attribute ENUM "InterfaceID" to the ServerWebExchange via exchange.getAttribute().put("InterfaceID",InterfaceID.A) after the JWT is validated, and currently uses "InterfaceID" to represent the different groups of users/different interface the user entered from.
JWTValidationFilter.java [Current]
switch(JWTValidator.validate(jwt).get("AZP")){
//if user is from company A or its partners
case "a":
case "aa":
exchange.getAttribute().put(InterfaceID.COMPANY_A_ACCESS);
break;
case "b":
exchange.getAttribute().put(InterfaceID.NORMAL_ACCESS);
...
}
For certain API endpoints (say /api/getSessionDocument), different "InterfaceID" fetches data from different DB/apis, as well as have different permission checking on top of that.
RequestController.java [Current]
#Autowired
APICallerUtil apiCallerUtil;
switch(exchange.getAttribute.get(InterfaceID)){
case "NORMAL_ACCESS":
apiCallerUtil.getDataFromApiA();
break;
case "COMPANY_A_ACCESS":
// call api B but check for permission from api D first
...
}
The endpoint's controller now has another switch statement, and to many code analyzers this have been a code smell. I have been trying to refactor this entire bit of code to use polymorphism to handle the different "getSessionDocument" flows, but i run into issues regarding the injection of util classes that calls specific APIs.
APICallerUtil.java class, exisiting class from the project, would prefer not to refactor this.
#Component
public class APICallerUtil{
#Value("${some uri to some API}") //different by environment and therefore cant be static final
private String uri1;
#Value("${some auth to some API}") //confidential
private String uri1AuthHeader;
//...
public JSONObject getDataFromApiA(String somekey){ //cant be static since uri1 is not static
//Some code that uses uri1 and apache httpclient
return data;
}
...
}
IBaseAccess.java
interface IBaseAccess{
default Mono<JSONObject> getSesssionDocument(ServerWebExchange e){return Mono.error("not implemented");}
}
RequestController.java [new]
#Autowired
APICallerUtil apiCallerUtil;
return exchange.getAttribute.get(InterfaceID).getSessionDocument(exchange);
NormalAccess.java
public class NormalAccess implements IBaseAccess{
//can i autowire APICallerUtil here?
//use constructor to pass the Util class reference here?
Mono<JSONObject> getSesssionDocument(ServerWebExchange e){
//need to call ApiA here
//need to call ApiC here
}
}
NormalAccess needs to call APICaller.getDataFromApiA(), but it needs a reference to the Spring managed instance of APICaller. What would be the "correct" way to pass the reference/autowire API caller into NormalAccess, or even better IBaseAccess (so that the implementing classes can use the Util bean)?
JWTValidationFilter.java [new]
switch(JWTValidator.validate(jwt).get("AZP")){
//if user is from company A or its partners
case "a":
case "aa":
exchange.getAttribute().put("InterfaceID",new CompanyAAccess(/*pass the util class here?*/));
break;
case "b":
exchange.getAttribute().put("InterfaceID",new NormalAccess(/*pass the util class here?*/));
...
}
I have tried several methods, but either I lack the knowledge on the specific Spring feature, or that method is deeemed a bad design choice by some, including:
Making the methods and fields in APICallerUtil static, via suggestions from Spring: How to inject a value to static field? and Assigning private static final field member using spring injection , then the Access classes can call the static methods.
Creating a contructor for IBaseAccess that consumes the APICallerUtil reference and store it inside. The JWTfilter would hold an autowired APICallerUtil and pass it in when the attribute is assigned.
Create a static class that provides the application context and Access classes use applicationContext.getBean("APICallerUtil"); to obtain the bean.
Use the #Configurable annotation? I could not find much documentation on how this works for interfaces/abstract-class.
I understand that there might not exist an absolute answer for this question, but regardless I'd like suggestion/feedback on which of these approaches are viable/good. Especailly concerning whether the APIUtil class should be static or not.
#Configuration
public class MyWebMvcConfigurationSupport extends WebMvcConfigurationSupport {
#Override
public FormattingConversionService mvcConversionService() {
FormattingConversionService f = super.mvcConversionService();
f.addFormatter(new DateFormatter("yyyy-MM-dd"));
return f;
}
}
#RestController
public class TestController {
#GetMapping
public Date test(Date date) {
return date;
}
}
When we access http://localhost:8080?date=2021-09-04, the argument type is converted through the DateFormatter's parse method, which relies on the SpringMVC framework to do the conversion. I wonder if the print method can also be invoked through the framework to return a string.
Do we need to manually invoke the print method, for example
#RestController
public class TestController {
#Resource
private FormattingConversionService conversionService;
#GetMapping
public String test(Date date) {
return conversionService.convert(date, String.class);
}
}
Inside the controller
You could use a class extending java.text.Format like SimpleDateFormatin your controller:
#RestController
public class TestController {
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
#GetMapping
public String test(Date date) {
return dateFormat.format(date);
}
}
At application level
Use DateTimeFormatterRegistrar to register your formats, like described in this tutorial.
Then you can register this set of formatters at Spring's FormattingConversionService.
Using Jackson
However if you would like to work with JSON or XML you should consider using FasterXML's Jackson. See similar question:
Spring 3.2 Date time format
This is the interface representing the environment in which the current application is running. It models two key aspects of the application environment: profiles and properties. The methods related to property access are exposed via the PropertyResolver superinterface.
A profile is a named, logical group of bean definitions to be registered with the container only if the given profile is active. Beans may be assigned to a profile whether defined in XML or via annotations; see the spring-beans 3.1 schema or the #Profile annotation for syntax details. The role of the Environment object with relation to profiles is in determining which profiles (if any) are currently active, and which profiles (if any) should be active by default.
Properties play an important role in almost all applications, and may originate from a variety of sources: properties files, JVM system properties, system environment variables, JNDI, servlet context parameters, ad-hoc Properties objects, Maps, and so on. The role of the environment object with relation to properties is to provide the user with a convenient service interface for configuring property sources and resolving properties from them.
Beans managed within an ApplicationContext may register to be EnvironmentAware or #Inject the Environment in order to query profile state or resolve properties directly.
In most cases, however, application-level beans should not need to interact with the Environment directly but instead may have to have ${...} property values replaced by a property placeholder configurer such as PropertySourcesPlaceholderConfigurer, which itself is EnvironmentAware and as of Spring 3.1 is registered by default when using context:property-placeholder/.
Configuration of the environment object must be done through the ConfigurableEnvironment interface, returned from all AbstractApplicationContext subclass getEnvironment() methods. See ConfigurableEnvironment Javadoc for usage examples demonstrating manipulation of property sources prior to application context refresh().
I would like to build a Spring application, where new components can be added easily and without much configuration. For example: You have different kinds of documents. These documents should be able to get exported into different fileformats.
To make this functionality easy to maintain, it should (basically) work the following way:
Someone programs the file format exporter
He/ She writes a component, which checks if the file format exporter is licensed (based on Spring Conditions). If the exporter is licensed a specialized Bean is injected in the application context.
The "whole rest" works dynamically based on the injected beans. Nothing needs to be touched in order to display it on the GUI, etc.
I pictured it the following way:
#Component
public class ExcelExporter implements Condition {
#PostConstruct
public void init() {
excelExporter();
}
#Bean
public Exporter excelExporter(){
Exporter exporter= new ExcelExporter();
return exporter;
}
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return true;
}
}
In order to work with those exporters (display them, etc.) I need to get all of them. I tried this:
Map<String, Exporter> exporter =BeanFactoryUtils.beansOfTypeIncludingAncestors(appContext, Exporter.class, true, true);
Unfortunate this does not work (0 beans returned). I am fairly new to this, would anyone mind to tell me how this is properly done in Spring? Maybe there is a better solution for my problem than my approach?
You can get all instances of a given type of bean in a Map effortlessly, since it's a built in Spring feature.
Simply autowire your map, and all those beans will be injected, using as a key the ID of the bean.
#Autowired
Map<String,Exporter> exportersMap;
If you need something more sophisticated, such as a specific Map implementation or a custom key. Consider defining your custom ExporterMap, as follows
#Component
class ExporterMap implements Map{
#Autowired
private Set<Exporter> availableExporters;
//your stuff here, including init if required with #PostConstruct
}
Is it possible to run multiple instance of the same service in the osgi framework?
More specific, I need to start multiple instances of a service, but each instance should recieve different parameters. This is because the services have similar functionality. But instead of writing a service for every variation, I want to reuse one implementing class.
I've already found the registerService method in the framework api.
ServiceRegistration<?> registration = bundlecontext.registerService(
className, class, null);
however, i seem to create only one instance of each class. Is there a workaround for this?
preferably something like
ServiceRegistration<?> registration = bundlecontext.registerService(
className + "#" + (++counter), new classInstance(), null);
Note that using Declarative Services with the corresponding annotations makes this quite easy, here's an excerpt from the Apache Sling codebase (ConfiguredFeature.java):
#Component(
name = "org.apache.sling.featureflags.Feature",
metatype = true,
configurationFactory = true,
policy = ConfigurationPolicy.REQUIRE)
#Service
public class ConfiguredFeature implements Feature {
#Property(label = "Name", description = "Short name of this feature")
private static final String NAME = "name";
private String name;
#Activate
private void activate(final Map<String, Object> configuration) {
this.name = PropertiesUtil.toString(configuration.get(NAME), "");
}
...
}
Using configurationFactory = true and policy = ConfigurationPolicy.REQUIRE causes one instance of this service to be created for each corresponding OSGi configuration, which is a natural way of creating multiple instances.
You could create a ManagedServiceFactory. The factory can register a new service for each configuration set in Configuration Admin.
I have a simple example here which uses Felix DependencyManager to register the component: https://github.com/paulbakker/osgicourse/tree/master/greeterfactory/src/greeterfactory
You have the parameters slightly wrong, or at least misleading:
ServiceRegistration<?> registration = bundlecontext.registerService(
className, class, null);
The second parameter to registerService is an object, not a class. This is an object you instantiate yourself. You can create as many as you like, in whatever way you like, before passing them to OSGi.
However if you are doing this with externally-supplied configuration data, should look into Declarative Services and their ability to receive config from the OSGi Configuration Admin service.
UPDATE
Taking another look at your question, I see the counter that you tried to add to the class name. This is not required and in fact not permitted either. Just call registerService multiple times.
I have a Grails application that needs to run a strategy that will likely be swapped out over time. I know Spring underlies Grails, so I was wondering if I had access to Spring's IoC container so that I could externalize the actual dependency in an xml file (note: I have never actually done this, but just know of it, so I may be missing something). My goal is to be able to do something like the following:
class SchemaUpdateService {
public int calculateSomething(){
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
IStrategy strat = (IStrategy) ctx.getBean("mystrat");
}
}
And then map the appropriate implementation in the beans.xml file. I assume this is supported in Grails. Does anyone have any documentation on how this would work? Do I really just need the Spring IoC library and it will just work? Thanks!
You define your beans in resources.xml or resources.groovy. The grails documentation is very clear about how to access the Spring application context.
You can access the application context from any Grails artefact using
ApplicationContext ctx = grailsApplication.mainContext
You can then use this to retrieve whichever beans you're interested in:
IStrategy strat = (IStrategy) ctx.getBean("mystrat")
In classes that don't have access to grailsApplication, you could use a helper such as the following to access the application context and the beans therein
class SpringUtils {
static getBean(String name) {
applicationContext.getBean(name)
}
static <T> T getBean(String name, Class<T> requiredType) {
applicationContext.getBean(name, requiredType)
}
static ApplicationContext getApplicationContext() {
ApplicationHolder.application.mainContext
}
}
However, this should only be necessary if you need to retrieve different implementations of the same bean at runtime. If the required bean is known at compile-time, just wire the beans together in resources.xml or resources.groovy
First of all, you want to define your strategy in your grails-app/conf/spring/resources.groovy:
beans = {
myStrat(com.yourcompany.StrategyImpl) {
someProperty = someValue
}
}
Then, you simply def the a property with the same name into your service:
class SomeGrailsService {
def myStrat
def someMethod() {
return myStrat.doSomething()
}
}
In any Grails artefact (such as services and domain classes), Grails will automatically give the myStrat property the correct value. But don't forget, in a unit test you'll have to give it a value manually as the auto-wiring does not happen in unit tests.
Outside of a Grails artefact, you can use something like:
def myStrat = ApplicationHolder.application.mainContext.myStrat
In Grails 2.0, Graeme et al are deprecating the use of the *Holder classes (such as ApplicationHolder and ConfigurationHolder), so I'm not quite sure what the Grails 2.0 approach would be...