I have a common situation: I have a scenario where object creation is handled by a builder.
e.g.
Class Client; // Creates a builder object.
Class Builder; // Can be used to set the desired params and then invoke build on it to return Service object.
e.g.-
client.createBuilder().withDefaultBinding(new StandardBinder())
.withDefaultMetricsFactory(new StandardMetricsFactory())
.withCacheSolution(cacheSolution)
.build();
However, Builder doesn't have standard setters. It performs some tasks and then sets the result into an internal object of Builder, so they can't be treated as properties as is.
I've read through: Spring: Using builder pattern to create a bean
I want to invoke the builder to retrieve the final object completely using Spring XML configuration.
I don't want to create a factory myself - I want to know if there is a way I can use an out-of-the-box Spring XML configuration to generate a service object in the above scenario? My understanding of Spring gives me the impression that this can be done by invoking a chain of setter methods (not setting the properties explicitly) on the builder objects and finally invoking a build to get the service object. If this is possible how would it be achieved?
There's no way to do this out-of-the-box with XML. Define a FactoryBean with appropriate properties (setters) for all the values you need and declare a bean of that custom FactoryBean type.
I've made it work when I wasn't able to "fix" the builder, and was only able to adjust config, not code.
Define a bean that uses "client" as a factory bean and "createBuilder" as the factory method.
Define another bean that uses that bean as a factory bean and "withDefaultBinding" as the factory method.
Define another bean that uses that bean as a factory bean and "withDefaultMetricsFactory" as the factory method.
Define another bean that uses that bean as a factory bean and "withCacheSolution" as the factory method.
Finally define your built bean that uses that bean as a factory bean and "build" as the factory method.
All but the last bean will actually point to the same object in memory, but that doesn't really matter.
I did have a similar case:
#Value("${some.property}")
String someProperty
#Bean
public JwtDecoder jwtDecoder() {
NimbusJwtDecoder.withJwkSetUri(someProperty).build();
}
Here's what I've done:
<bean id="jwtDecoder" class="org.springframework.security.oauth2.jwt.NimbusJwtDecoder" factory-bean="jwtDecoderBuilder" factory-method="build"/> <!-- factory-bean -->
<bean id="jwtDecoderBuilder" class="org.springframework.security.oauth2.jwt.NimbusJwtDecoder" factory-method="withJwkSetUri"> <!-- NO factory-bean -->
<constructor-arg name="jwkSetUri" value="${some.property}"/>
</bean>
NimbusJwtDecoder source code:
https://github.com/spring-projects/spring-security/blob/5.2.2.RELEASE/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoder.java
Related
Is it possible to define a prototype bean, using XML config or annotation-based config such that I can get an instance of the bean with a custom parameter value? My use case is a message queue handler that makes API calls with different parameter values that are supplied in the inbound message.
In this case it seems I can do one of two things:
Get an instance of my prototype-scope bean and then call setters to customize it to be specific to the inbound message.
Construct a new instance of the bean class using a plain new MyPrototypeBean() and then call setters to customize the instance.
Perhaps a different way of wording my question is: What is the benefit of using a prototype-scope bean vs. using a simple Java constructor?
To get a prototype bean from another bean while passing arguments to constructor you can use <lookup-method> (XML Configuration) or #Lookup (annotation-based configuration).
If you want to get the prototype instance from "unmanaged" code (not from a bean) or you don't want to use the lookup methods, you can achieve the same using org.springframework.beans.factory.BeanFactory.getBean(String beanName, Object...).
Answering your second question, difference between a prototype-scope bean and using a simple Java constructor is that the prototype-scope bean still have access to Spring container's features. This includes, but it's not limited to the following: it can have collaborators provided in XML configuration (<property name="someCollaborator" ref="..."/>) or with annotations (#Resource, #Autowired, ...), t can implement Spring-aware interfaces (like ApplicationContextAware so that the prototype bean itself has access to the container).
Is it possible to inject new instances of prototype scoped beans to Controller's method arguments at runtime using annotations in Spring? So whenever the method is called, Spring would inject the qualifying bean as its argument, familiarly as it injects #ModelAttribute. As far as I know, #Autowired fields are injected only once when context is created. Obtaining the bean from context's factory method isn't an option, as that would expose framework to its component, thus violating the hollywood principle.
I have almost completed reading Spring in Action book and have been reading Spring Reference a lot, but haven't found any info regarding this question.
You have a couple of options.
Define a prototype bean and inject that wrapped in an ObjectFactory
#Autowired
private ObjectFactory<PrototypeBean> factory;
You can then retrieve it in your handler method. For example
#RequestMapping("/path")
public String handlerMethod() {
PrototypeBean instance = factory.getObject();
instance.someMethod();
return "view";
}
Every time you call factory.getObject(), you'll get a new instance.
As for doing this directly, no, Spring MVC does not have a built-in feature for having beans injected while invoking handler methods, with #Autowired or otherwise.
However, the HandlerMethodArgumentResolver API allows you to define an implementation for any type of parameter you want. You can define a new annotation and use it to annotate the appropriate handler method parameter(s). The implementation would look for the annotation and resolve an instance from an injected ApplicationContext. You could do this by name, by type, however you want.
I'm writing a service registry class. This service registry will scan packages for annotated classes and then populate some internal map. What I need then, is to be able to query for services (by String name) using some method (let's say Object get(String name)). This method will then search internal map for a service with such name and returns instance.
What I'm doing right now, is having this ServiceRegistryBean implement ApplicationContextAware and BeanDefinitionRegistryPostProcessor and a list of Strings (package names) given on construct.
Then, as soon as the bean is constructed, registry post processor kicks in (see note) and the registry class adds the service classes as new beans (singleton, lazy loaded) to the spring bean registry. Then, getting the service instance is as simple as requesting a bean from context, returning singleton instance.
My question is: is there a better way in Spring to do this? I've looked into bean factories, but it does not seem to me the same. Support for auto-wiring and DI in service instances is essential, that's why I want Spring to instantiate it. Also, I like the idea of Spring taking care of singletons.
Note: I've found out, that when I inline the bean creation in <constructor-arg> (that is, bean is not named and is just an instance passed as constructor argument of other bean - in my case, I'm passing registry as a parameter to other constructor), BeanDefinitionRegistryPostProcessor interface methods (namely public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)) is not called at all! I'm quite sure, it is some behavior of Spring I don't know about, but I was not able to find proper documentation for the post-processor.
Thank you for any hints or insights!
Scanning for custom annotations it's already supported, you only need to add a include-filter to <context:component-scan> tag, ie
<context:component-scan base-package="org.example">
<context:include-filter type="annotation" expression="some.Annotation"/>
</context:component-scan>
see http://static.springsource.org/spring/docs/current/spring-framework-reference/html/beans.html#beans-scanning-filters
If you turn on default-lazy-init I suppose that the DI Container is ready to use as Service Locator Registry.
About the note, only root bean definitions are taken into account when looking for BeanFactoryPostProcessors, inner beans are ignored.
Usually, scanning and registering beans is done by BeanDefinitionParsers instead because you known when the beans are registered and beans are visible for tools, like STS Spring Bean Explorer, but using a BeanDefinitionRegistryPostProcessor is correct. The interface ensures that beans are defined before other BeanFactoryPostProcessors run.
When I get a spring bean (via getBean()), is there any way to verify from java code that the bean has been defined with scope=prototype ?
Spring config:
<bean class="foo.Bar" scope="prototype" />
Java:sc
MyBean bean = springApplicationContext.getBean("MyBean");
I could just instantiate it twice and compare the objects, but I'd like to avoid unnecessary object creation. Something like the opposite of this answer would do the trick: https://stackoverflow.com/a/9125610/156477
You have a API boolean isPrototype(String name) in ApplicationContext to check it.
I have a factory-ish bean that creates a number of objects on startup, and I want these objects to themselves be Spring beans.
If I were creating a single object I could do instantiation with a factory method, eg. (from Spring docs section 4.3.2.3):
<!-- the factory bean, which contains a method called createInstance() -->
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
<!-- inject any dependencies required by this locator bean -->
</bean>
<!-- the bean to be created via the factory bean -->
<bean id="clientService"
factory-bean="serviceLocator"
factory-method="createClientServiceInstance"/>
And if I knew ahead of time that I'd have n objects, I could call n different methods, but I don't - my factory creates an arbitrary number of objects not known ahead of time.
Does anyone know how to do this?
The goal is for them to be "proper" Spring beans like the above would produce; specifically, they should be eligible for autowiring both as sources and targets. Note this means I don't just want to return a Collection and have that be the bean.
I'm using XML-configured Spring 3.1.
Seems like you need dynamic bean creation...
Never tried it before but as mentioned in this question, you might try using BeanDefinitionBuilder. Seems it has all you need. Use it from your factory bean (which doesn't really need to be defined as factory bean now).
EDIT: I found a nice usage example here.
Something like:
String className = ... // get class name from wherever you get it
// Build your dynamic bean:
BeanDefinitionBuilder bdb = BeanDefinitionBuilder.genericBeanDefinition(className);
bdb.setSingleton(true);
// add dependencies:
bdb.addDependsOn(dependeeBeanName);
// Eventually - validate it and get it:
AbstractBeanDefinitionb bean = db.getBeanDefinition();
// I guess only now you get other already existing beans
// and make them depend on the one you created in the same way