i wanna make request scoped configuration for Jackson serializer based on request parameter, so my problem is the configuration runs in a different thread and only runs when the app stars, how i can make java reconfigure Jackson serializer in every request ?
It's not possible to have request scoped config. Instead make the Jackson serializer bean request scoped and return instance with necessary config.
You can use approach described here
instanciation of a request scoped bean
#Configuration
public class MyBeansConfig {
#Bean
#Scope(value="request", proxyMode=ScopedProxyMode.TARGET_CLASS)
public RequestScopedBean requestScopedBean() {
//if needed set the required parameters
return new RequestScopedBean();
}
}
Just return here your serializer instance. Then just autowire it wehre it's necessary
Related
Originally, there was a service instance to access the database and now we want to add a readonly instance. So I add the serviceReadonly in my configuration.
#Configuration
public class Config {
#Bean Service service() {...};
#Bean Service serviceReadonly() {...};
#Bean Proxy proxy() {return new Proxy(serviceReadonly())}; // replace the original Proxy(service())
}
But, the service is also autowired to Proxy
#Component
public class Proxy {
#Autowired
public Proxy(Service service) {this.service = service;}
}
I am confused which Service is injected in my API? service or serviceReadonly?
#Component
public class API {
#Autowired
public API(Proxy proxy) {this.proxy = proxy;}
}
The Proxy and API classes are in another shared library and avoiding change to the library is preferred. Also, the service is autowired to other components.
Short answer: #Bean Service service()
Explanation: Excerpt from the Spring documentation here
Autowiring by property name. Spring looks for a bean with the same
name as the property that needs to be autowired. For example, if a
bean definition is set to autowire by name, and it contains a master
property (that is, it has a setMaster(..) method), Spring looks for a
bean definition named master, and uses it to set the property.
I assume it will be #Bean Service service() because the Spring would find the bean with same name as the property i.e. Service as defined in official Spring guide.
You may also need to look into #Qualifier annotation. It is because if there is not exactly one bean of the constructor argument type in the container, a fatal error is raised, as mentioned in Spring documentation here. Have you checked if you receive this error of NoUniqueBeanDefinitionException? In that case you can use #Qualifer annotation to specify the bean you want.
I just found a behaviour of Spring that I cannot understand. I am using Spring Boot 1.5.x.
In a configuration class, I declared two different beans.
#Configuration
class Config {
#Bean("regularRestTemplate")
public RestTemplate regularRestTemplate(String toLog) {
return new RestTemplateBuilder().setConnectTimeout(100)
.setReadTimeout(100)
.additionalInterceptors((request, body, execution) -> {
log.info("Inside the interceptor {}", toLog);
return execution.execute(request, body);
})
.build();
}
#Bean("exceptionalRestTemplate")
public RestTemplate regularRestTemplate() {
return new RestTemplateBuilder().setConnectTimeout(100)
.setReadTimeout(100)
.build()
}
}
Then, I have a class that should use the bean called exceptionalRestTemplate.
#Component
class Client {
private RestTemplate restTemplate;
#Autowired
public Client(#Qualifier("exceptionalRestTemplate") RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
// Code that uses the injected rest template
}
Since I specified the name of the bean I want to be injected using the #Qualifier annotation, I would expect that Spring injects the bean called exceptionalRestTemplate. However, the bean called regularRestTemplate is actually used during the injection process.
It turns out that the problem was in the name of the methods that declare the beans in the configuration class. Both are colled regularRestTemplate. Changing the second method name, solve the problem.
My question is, why? I know that Spring uses the names of classes and methods annotated with the #Bean or with the #Component, #Service, etc... annotations to give a name to Java object inside the resolution map. But, I supposed that giving a name inside these annotations would override this behaviour.
Does anybody tell me what's going on?
Bean qualifier and bean name are different meanings. You qualified new bean but tried to override it (arguments don't matter). In your application, you cannot override beans so you have the only first one.
You can check this 'theory'. Add a parameter in your configuration
spring.main.allow-bean-definition-overriding=true
and start your application again. After that, you will have only a second bean.
This is an explanation of the collision. But the solution is a separation of beans to different configurations.
I was trying to configure promethues in my code and I just had to create a bean like below. I was wondering how spring recognised CollectorRegistry. How did spring instantiate all the necessary variable for CollectorRegistry and setup all the necessary cofnfiguration?
#Component
public class TestProm{
public TestProm(CollectorRegistry registry){
// Some initialization code here
}
}
However, when I tried to define it in another way by defining a #Bean in my #Configuration class, it didn't seem to work properly as my own constructor for CollectorRegistry didn't have all the necessary properties.
#Configuration
public class PromConfiguration{
#Bean
public TestProm getTestProm() {
return new TestProm(new CollectorRegistry());
}
}
public class TestProm{
public TestProm(CollectorRegistry registry){
//Some code here
}
}
How do I recognise/replicate the initialization of CollectorRegistry done by spring when I do my custome implementation.
How did spring instantiate all the necessary variable for CollectorRegistry and setup all the necessary cofnfiguration?
In the first example you require a Bean of type CollectorRegistry and Spring will actually create such bean for you if you have spring-boot-starter-actuator and Prometheus dependencies on your classpath and you have autoconfiguration enabled :
if you use #EnableAutoConfiguration
if you are using Spring Boot and #SpringBootApplication annotation (#EnableAutoConfiguration is part of this annotation underneath) :
...
#EnableAutoConfiguration
#ConfigurationPropertiesScan
...
public #interface SpringBootApplication
In this case Spring will scan the classpath and load all configurations. The bean that you are interested in is part of PrometheusMetricsExportAutoConfiguration :
#Bean
#ConditionalOnMissingBean
public CollectorRegistry collectorRegistry() {
return new CollectorRegistry(true);
}
In the second example the instance of CollectorRegistry is not managed by Spring because you create it through new keyword. However it should work as CollectorRegistry has default constructor which initializes autoDescribe field to false. And the default Bean of this class which is created by Spring (in a way described above) has this field set to true. So the value of this field is the source of your differences.
Also if this instance is not managed by Spring - it prevents it to be injected into other components which require it. As the scope of CollectorRegistry is Singleton (shown above) other beans might require to share the instance to work properly (for example some beans might want to register/deregister collectors) but if you create CollectorRegistry like that with new keyword - you will not get the singleton instance but a new instance which cannot be shared across other beans.
How do I recognise/replicate the initialization of CollectorRegistry done by spring when I do my custom implementation?
If you want to use the default CollectorRegistry (assuming you want to use the bean that is created by default in the way described above) just inject bean of this type to your beans and it should be enough.
I have a library which produces beans into a Spring context for use by clients. The beans I produce are configured by Spring. I need to add a new bean to my context in order to satisfy a dependency of a new bean I'm publishing. However, I believe some of my clients already have an instance of this bean and are autowiring it by type. So I have something like this:
// Code in my Library
#Component
public class PublicUtilityClass {
// This is all new code in my library
private NewDependency newDependency;
public void newCapability() {
newDependency.doNewThing();
}
#AutoWired
public void setNewDependency(NewDependency newDependency) {
this.newDependency = newDependency;
}
// Other library code omitted.
}
How can I use Spring to instantiate NewDependency and inject it into PublicUtilityClass without impacting customers who already have a NewDependency bean in their context?
You should look at #Qualifier annotation. Qualifier allows you to have multiple instance of your bean
I have following situation. There is POJO which has autowired implementation of an interface, using some spring magic as shown bellow. However this dependency doesn't get resolved if creation of channels is managed via spring bean. It only works if POJO factory creates channels. Example bellow.
#Controller
public class Test{
#RequestMapping(value = "/load", method = RequestMethod.GET)
public #ResponseBody String testConfiguration() {
// this is pojo and here it works, channels within have wired interface implementation
StaticFactory.getChannels(null);
// if i call same method within spring managed bean (#Service)
// then it doesnt work
System.out.println("channels created");
return "alive";
}
}
Created Channels are POJO but they have autowired interface implementation, which should be enabled with the following in constructor:
public DummyChannel() {
// enables dependency injection of spring managed beans into POJO
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
}
public class StaticFactory {
public static List<SmppChannel> getChannels(Map<ChannelMode, Integer> channelsDefinition) {
List<SmppChannel> dummyChannels = new ArrayList<>();
DummyChannel d = new DummyChannel();
System.out.println("here");
dummyChannels.add(new DummyChannel());
return dummyChannels;
}
}
Now, this thing works if i have non-spring managed Factory. Regardless if mentioned factory is static or not when it creates channels, they have properly wired interface implementation.
However, if i copy paste exactly same code form the factory into Spring managed Bean annotated with #Service, wired dependency is null in created channel.
Could somebody tell me what am i missing here, why things get injected when the factory of channels is not managed by the Spring ?
Edit Solution: // Okay, so the problem is in the fact that DummyChannels enable autowiring support in constructor while Spring beans are still not loaded. It is working if i do this within method that should access autowired service rather then the constructor of DummyChannel.
Have you enabled annotation-config and component-scan in your xml or java configuration? Is the class that you want to inject annotated with #Service or #Resource?
Are you building a Web Service with JAX-WS? If yes, then I think your class (the one doing the autowiring) must implement SpringBeanAutowiringSupport so that Spring's IoC container can handle the injection.