Can I programmatically determine if a spring bean is not singleton? - java

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.

Related

Spring without getBean(..)

I'm trying to get a better understanding of the #Autowired annotations component scanning, but all the examples I found so far use context.getBean(..) at some point to get at least one Bean to start with.
I also read that doing that is considered bad practice , but I can't seem to find any information on how to do it without context.getBean(..)
Could somebody please enlighten me with an example and information on how to do this ?
Define your bean in xml and use
<context:component-scan base-package="com" />
<mvc:annotation-driven />
Bean def
<bean id="processEngine" class="com.processEngine">
<property name="processEngineConfiguration" ref="processEngineConfiguration" />
</bean>
now you can get bean as following
#Autowired
private ProcessEngine processEngine;
how it works
spring scans the bean's recipes either from xml or java configuration. then spring creates a beanDefinitions which are 'loaded' into BeanFactory. BeanFactory triggers a set of BeanPostProcessors (BPP) which are scanning classes for particular annotations like Autowired/Resource/PostProcessor and etc. and do appropriate actions. in case when your class contains #Autowired annotation, AutowiredAnnotationBeanPostProcessor would auto wire required field (dependencies), and when creation of an object is done and all BPP worked out, object is ready to be used by the app, from this point your code can get 'ready' objects from container.
there are some cases when you would need to access this beans from the code which is out of spring's control and not managed by container. in order to do so, you would need to get the ApplicationContext (container) and call #getBean specifying either name or type. using applicationContext directly is not a good practice because there are some problems that you can come to, f.ex. id of a bean might be changed and if you refer to bean by id then NPE would be thrown.
configuration
there are several approaches to configure spring to scan the classes for finding bean recipes. one would be defining component-scan, in this case classes which are located in the path that you've set and having any of valid spring annotations like #Component, #Service, #Repository, #Controller (for web container) would be considered. another way would be specifying each bean separately using <bean> or #Bean.
examples.
if you want to create a web app then you should see DispatcherServlet with ContextLoaderListener classes. this classes would boot your app and load everything according to configuration. f.ex. here,
but if you want to create a desktop app, then you would end up with something like this
From time to time (usually when not using Spring Boot), I use something along the lines of the following code:
public static <T> T autowire(ApplicationContext ctx, T bean) {
ctx.getAutowireCapableBeanFactory().autowireBean(bean);
return bean;
}
In my main, I create an instance of the main application class that contains a few #Autowired annotations for the main services / entry points to my Spring application.

How to initialize a bean which follows the Builder Pattern

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

Spring: Xml based Autowiring a list of beans by interface type

With Spring it is possible to inject a list of beans by the interface class like:
#Component
public class Service {
#Autowire
private List<InterfaceType> implementingBeans;
...
}
All defined beans that implement this interface will be present in this List.
The annotation based approach is not possible for me, as the Service class is in a module that must not have spring dependencies.
I need to use this mechanism from outside via xml configuration.
<bean id="service" class="...Service">
<property name="implementingBeans">
??? tell spring to create a list bean that resolves all beans of the interfaceType.
</property>
</bean>
Does anyone know how to solve this?
EDIT: Additionally, there are more than one spring applications that use this service. So the best solution would be to handle this szenario completely via xml configuration. I can then copy the xml parts to all spriong applications that need this.
I want to avoid having a kind of initializer bean that gets the service injected and must then be copied to all spring applications.
Kind regards.
An XML-only solution would simply have you declare a <bean> of the "external" type and provide an autowire value of "byType".
Controls whether bean properties are "autowired". This is an
automagical process in which bean references don't need to be coded
explicitly in the XML bean definition file, but rather the Spring
container works out dependencies.
[...]
"byType" Autowiring if there is exactly one bean of the property type in the container. If there is more than one, a fatal error is
raised, and you cannot use byType autowiring for that bean. If there
is none, nothing special happens.
The explanation is a little confusing in that we expect multiple InterfaceType beans, but the actual field is of type List and Spring will be able to dynamically instantiate one and add all the InterfaceType beans to it, then inject it.
Your XML would simply look like
<bean id="service" class="...Service" autowire="byType">
</bean>
My original suggested solution made use of SpEL.
In the module that does have Spring dependencies, create a DTO
#Component(value = "beanDTO")
public class BeanDTO {
#Autowire
private List<InterfaceType> implementingBeans;
public List<InterfaceType> getImplementingBeans() {
return implementingBeans;
}
}
and then use SpEL to retrieve the value of implementingBeans from the beanDTO bean.
<bean id="service" depends-on="beanDTO" class="...Service">
<property name="implementingBeans" value="{beanDTO.implementingBeans}" />
</bean>
Spring will create the BeanTDO bean, inject all the beans that are of type InterfaceType. It will then create the service bean and set its property from beanDTO's implementingBeans property.
Following comments on question:
In an effort to be more JSR 330 compliant, Spring has introduced support for Java EE's javax.inject package. You can now annotate your injection targets with #javax.inject.Inject instead of #Autowired. Similarly, you can use #Named instead of #Component. The documentation has more details.

Spring: Creating an arbitrary number of beans using a factory bean

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

spring 3.0 force singleton bean

<bean id="data.emf"
class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean" >
<property name="persistenceUnitName" value="transactions-optional" />
</bean>
from what i know by default all bean are singleton (according to document) but i somehow still getting duplicated creating of entitymanagerfactory. is there any parameter i can set for bean above in spring 3.0 to force singleton? the problem only appear in gae production, on hosted mode, no problem
You can force a bean to be a singleton like this:
<bean scope="singleton" ... >
</bean>
You generally don't need to do this, however, since singleton is the default scope, and there's no way to change the default.
The Spring DEBUG-level logs will generate entries every time a bean is instantiated, so have a look through there to see when and where your bean is being processed.
Maybe the problem doesn't come form the scope. Are you sure you haven't defined another bean in anther place of the program (for example with an annotation) or in another context file? Comment that bean definition and try if it can find a instance of it without declaring it here.

Categories

Resources