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
Related
I have a bean defined in a appContext named MyBean in MyProject1.
I have in other app that injects all the bean definitions of MyProject1 (including MyBean).
Now I need to override that bean but there is no easy way , so in MyProject2 I make
<bean primary="true" class=MyBean />
It works great, my question is....
What will happen with all others that were using MyBean? Will now use the new bean with the primary=true or how can I specify which should use this new bean and which should keep using the old one?
Following spring documentation primary bean is used only if there are some candidates to be injected. All created beans are in the context.
If you need only your primary bean to be injected, you can use:
#Autowired
private MyBean myBean;
So all your old beans will be replaced with primary one.
If you need to handle all MyBean beans (for example you do Chain Of Responsibilities) you can inject:
#Autowired
private List<MyBean> myBeans;
and injected object would contain all your bean instances (primary and nonprimary). As Usual primary bean can be accessed from list by 0 index: myBeans.get(0). All alternative markers (for example filter by vendorType...) to detect bean that you needs you should specify and handle in you code filtering collection, but in usual way if project architecture doesn't have issues you have no needs make alternative markers filtering bean objects in collection.
Do not forget about singleton if you need only one bean in your context.
If you have specified different bean unique names you can inject with #Qualifier (sometimes using #Resource from java API javax.annotation.Resource) specifying correspond name as parameter to detect bean by name.
Spring provides ability to inject properties using SpEL. May be they'll provide new functionality to inject beans using SpEL also (it could help you in your issue in best way).
Use profiles or #Conditional. #Qualifier is meant for resolving conflict for autowire, not for deactivating all but one. When using #Qualifier, all the candidate beans are still active.
Using profiles, when you want to use the bean from project2, simply start the app with a profile=project2; the link above describes multiple ways to do that.
See my answer here for a complete example of using #Conditional.
What is the getBean() method doing here and how does it work in a program?
ApplicationContext aplicntxt = new
ClassPathXmlApplicationContext("springconfig.xml");
Hello h = (Hello) aplicntxt.getBean("springconfig.xml");
h.display();
Hello h2 = new Hello(); //if I write this
h2.display();
My question is why h2.display retrieves null value and h.display retrieves the stored values through springconfig.xml?
Please tell me what does
ApplicationContext aplicntxt = new ClassPathXmlApplicationContext("springconfig.xml");
do first?
Are all the values of xml file stored to the pojo class setters at first step?
Then we are storing the values to an object h
by doing
Hello h = (Hello) aplicntxt.getBean("springconfig.xml");
Your question is essentially "How does spring work", this is covered extensively by the official documentation
The following creates all the beans defined by the springconfig.xml, that is it creates objects of the given types, and injects any properties you've defined, depending on your exact configuration it may also do things like package scanning, annotation processing etc.
ApplicationContext aplicntxt= new ClassPathXmlApplicationContext("springconfig.xml");
XML
<bean class="org.example.Hello" id="foo" />
<bean class="org.example.Hello" id="bar" />
This would create an objects of type Hello and tag them with the IDs "foo" and "bar"
All the beans are stored against their IDs for later retrieval via getBean(), note this takes the bean ID or name, not the XML file.
Hello h = (Hello) aplicntxt.getBean("foo");
What you are doing in code is called Spring Dependency Injection which let you define application beans and inject them when you need. like getBean() method that you use in your code which inject specific bean from XML file.
From spring doc
The interface org.springframework.context.ApplicationContext represents the Spring IoC container and is responsible for instantiating, configuring, and assembling the aforementioned beans. The container gets its instructions on what objects to instantiate, configure, and assemble by reading configuration metadata. The configuration metadata is represented in XML, Java annotations, or Java code. It allows you to express the objects that compose your application and the rich interdependencies between such objects.
Several implementations of the ApplicationContext interface are supplied out-of-the-box with Spring. In standalone applications it is common to create an instance of ClassPathXmlApplicationContext or FileSystemXmlApplicationContext. While XML has been the traditional format for defining configuration metadata you can instruct the container to use Java annotations or code as the metadata format by providing a small amount of XML configuration to declaratively enable support for these additional metadata formats.
Now Your Question and its simple ApplicationContext activates the object(it is eager container) and looks for the beans declared so the objects are loaded whenever it is called.
Now consider if you have two beans , and you need one of them you will find that bean by using ctx.getBean("beanId") to load instance and to provide data declared with this bean where beanId will tell which object to load.
consider following example
<bean id="a" class="package.Hello" />
//here it will look for bean name and then loads the class
Now when You call it like
ApplicationContext ctx=new ClassPathXMLApplicationContext("configuration.xml");
//will look for configuration.xml bean file if it is not in path then throw execption.
now
Hello hello=ctx.getBean("a");
// if configuration.xml contains any bean named "a" and holds reference to class(hello) load it immediately and return object of that class
is same as
Hello hello=new Hello();
hello.method();
and it is creating object of Hello class by using xml
From looking at this quickly, it appears that this code uses spring to initialize the Hello object with the values specified in the spring bean found in the xml file (I'm assuming that's what's in the filr, but I could be more specific if you post it).. When you create a second hello object you are using the constructor's default value for display, which is null.
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
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.