In an Spring Application it is possible to retrieve all (?) Beans with applicationContext.getBeansOfType(Object.class). This is of course only possible, after all Beans have been created.
So, if I call this method in the constructor of a Bean, I have to be lucky, to be the last Bean to be created, to have access to all of them.
As far as I understand the life cycle of Spring Beans, there is a phase in which BeanDefinitions are created, before the Beans are initialized.
How is it possible to retrive all created BeanDefinitions in the constructor of a Bean?
Can I also retrive the types (as Class) of those BeanDefinitions? The type BeanDefinition seems to only provide the "current bean class name of this bean definition".
Or is the only way to get those types after all Beans have been constructed (e.g. #PostConstruct)?
Maybe this code could help
for (String name : applicationContext.getBeanFactory().getBeanDefinitionNames()) {
BeanDefinition beanDefinition = applicationContext.getBeanFactory().getBeanDefinition(name);
String className = beanDefinition.getBeanClassName();
Class<?> clazz = Class.forName(className);
}
The loop gets you all the BeanDefinitions and then you load the class for each and do what you want?
By the way this might not be a good way to use Spring but it will work.
You can create a last bean by putting it for example in an #Configuration class with a minimum initialization order, so that it is the last one with
#Order(Ordered.LOWEST_PRECEDENCE), that would be it:
#Configuration
#Order(Ordered.LOWEST_PRECEDENCE)
public class Last {
#Autowired
ApplicationContext applicationContext;
#Bean
public String lastBean() {
applicationContext.getBeanDefinitionNames(); //retrive all created BeanDefinitions in the constructor of a Bean
applicationContext.getBeansOfType(Object.class); //retrive the types (as Class)
return "lastBean";
}
}
Related
I want to find all beans that are not injected into other beans, thus I can remove them to make spring start up faster. Any ideas? Thanks in advance.
From ConfigurableBeanFactory#getDependentBeans Javadoc, I see that there's a method we can invoke to get an array of beans that depends on the bean name we provide. Tracing backwards to how we can get the bean factory. You could probably do the following if you can get a hold of the GenericApplicationContext:
Get the bean factory from the context.
Iterate through the bean definition names in the bean factory.
Call ConfigurableBeanFactory::getDependentBeans to see if anything depends on it.
#Component
public class Example {
#EventListener
public void contextRefreshed(ContextRefreshedEvent event) {
// Could also just autowire the context directly
GenericApplicationContext context = (GenericApplicationContext) event.getApplicationContext();
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
String[] beanNames = beanFactory.getBeanDefinitionNames();
for(String beanName : beanNames) {
String[] dependentBeanNames = beanFactory.getDependentBeans(beanName);
if (dependentBeanNames.length <= 0) {
// bean with nothing depending on it
}
}
}
}
Edit:
This solution isn't perfect, but would probably be useful as a starting point. There are beans that could have nothing depend on it, but are used in the application. A good example would be your controllers (classes annotated with #Controller). From what I tested out, it had 0 dependent beans but the request mapping methods it holds is clearly being executed and referenced somehow.
I am confused about this little topic. Somewhere I read that if a class is annotated with #Component, it is spring managed bean and whenever it is required, spring will provide it. I am confusing it with scope of a bean. Let me explain:
Let's say a class
#Component
public class Example{ }
If I instantiate this class in other class using new Example(), would container always provide me the same Example object all the time? Or would it return me new object every time?
Here comes the confusing part:
If in the same class I have two beans like this:
#Component
public class Example {
#Bean DataSource sqlDataSource() {
// some logic
}
#Bean #Scope("prototype") SomeObject getSomeObject() {
return new SomeObject(sqlDataSource()); //**
}
}
What will happen in this case? sqlDataSource() method invocation would return the same object again and again every time SomeObject bean is requested, or new instance of DataSource will be returned every time SomeObject is requested?
#Bean is a method-level annotation that indicates Spring to create a bean when that method is invoked. It means to have the same functionality thatn tag in XML config.
This annotation must be used inside of a #Configuration annotated class, otherwise if you invoke the method from another method it will be a normal java new operation, not spring's. See this post --> #Bean inside class with #Configuration and witout it
Bearing this in mind new SomeObject(sqlDataSource()); would be equal to new SomeObject(new SqlDataSource());
if you annotate Example with #Configuration what will happen is that you'll get always a new SomeObject instance with the same sqlDataSource object, this means that Spring will take care of creating ONLY ONE sqlDataSource because it is singleton.
#Bean DataSource sqlDataSource() {
// some logic
}
This defines a singleton instance of DataSource. So everytime you request an instance of SomeObject a new SomeObject will be created (while it is defined in the prototype scope) but all of them will share the same DataSource object (since it's a singleton bean).
Is there any way to use two different ids for referring to the same instance in a Spring context?
What I'm trying to find is a way for aliasing the bean id, for a singleton scope.
http://docs.spring.io/autorepo/docs/spring/4.1.3.RELEASE/javadoc-api/org/springframework/context/annotation/Bean.html
Bean Names section
the name attribute may be used. Also note that name accepts an array of Strings. This is in order to allow for specifying multiple names (i.e., aliases) for a single bean.
#Bean(name={"b1","b2"}) // bean available as 'b1' and 'b2', but not 'myBean'
public MyBean myBean() {
// instantiate and configure MyBean obj
return obj;
}
You could use the #Bean annotation (Spring 3.0+) with its name value.
The name of this bean, or if plural, aliases for this bean. If left unspecified the name of the bean is the name of the annotated method. If specified, the method name is ignored.
public #interface Bean {
String[] name() default {};
...
}
For example, your bean of C class will be available as a or b (BUT not c) in a Spring context.
public #Bean(name = {"a", "b"}) C getInstance() { ... }
I'm working with some existing code and it is doing things I haven't seen before. I've dealt with autowiring prototype beans into singletons using method injection or getting the bean from the context using getBean(). What I am seeing in this code I am working on is a bean that is a prototype and retrieved using getBean(), and it has autowired dependencies. Most of these are singleton beans, which makes sense. But there is an autowire of another prototype bean, and from what I see, it does seem like it is getting a new bean. My question is when you autowire a prototype into a prototype, will that give you a new instance? Since the autowire request is not at startup but rather when this bean is created, does it go and create a new instance? This goes against what I thought about autowire and prototype beans and I wanted to hear an answer from out in the wild. Thanks for any insight. I'm trying to minimize my refactoring of this code as it is a bit spaghetti-ish.
example:
#Scope("prototype")
public class MyPrototypeClass {
#Autowired
private ReallyGoodSingletonService svc;
#Autowired
private APrototypeBean bean;
public void doSomething() {
bean.doAThing();
}
}
#Scope("prototype)
public class APrototypeBean {
private int stuffgoeshere;
public void doAThing() {
}
}
So when doSomething() in MyPrototypeClass is called, is that "bean" a singleton or a new one for each instance of MyPrototypeClass?
In your example, the APrototypeBean bean will be set to a brand new bean which will live through until the instance of MyPrototypeClass that you created is destroyed.
If you create a second instance of MyPrototypeClass then that second instance will receive its own APrototypeBean. With your current configuration, every time you call doSomething(), the method will be invoked on an instance of APrototypeBean that is unique for that MyPrototypeClass object.
Your understanding of #Autowired or autowiring in general is flawed. Autowiring occurs when an instance of the bean is created and not at startup.
If you would have a singleton bean that is lazy and that bean isn't directly used nothing would happen as soon as you would retrieve the bean using for instance getBean on the application context an instance would be created, dependencies get wired, BeanPostProcessors get applied etc.
This is the same for each and every type of bean it will be processed as soon as it is created not before that.
Now to answer your question a prototype bean is a prototype bean so yes you will receive fresh instances with each call to getBean.
Adding more explanation to #Mark Laren's answer.
As explained in Spring 4.1.6 docs
In most application scenarios, most beans in the container are
singletons. When a singleton bean needs to collaborate with another
singleton bean, or a non-singleton bean needs to collaborate with
another non-singleton bean, you typically handle the dependency by
defining one bean as a property of the other. A problem arises when
the bean lifecycles are different. Suppose singleton bean A needs to
use non-singleton (prototype) bean B, perhaps on each method
invocation on A. The container only creates the singleton bean A once,
and thus only gets one opportunity to set the properties. The
container cannot provide bean A with a new instance of bean B every
time one is needed.
Below approach will solve this problem, but this is not desirable because this code couples business code with Spring framework and violating IOC pattern. The following is an example of this approach:
// a class that uses a stateful Command-style class to perform some processing
package fiona.apple;
// Spring-API imports
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class CommandManager implements ApplicationContextAware {
private ApplicationContext applicationContext;
public Object process(Map commandState) {
// grab a new instance of the appropriate Command
Command command = createCommand();
// set the state on the (hopefully brand new) Command instance
command.setState(commandState);
return command.execute();
}
protected Command createCommand() {
// notice the Spring API dependency!
return this.applicationContext.getBean("command", Command.class);
}
public void setApplicationContext(
ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
So, there are 2 desirable ways to solve this problem.
1. Using Spring's method injection
As name suggests, Spring will implement & inject our abstract method by using #Lookup annotation from Spring 4 or tag if you use xml version. Refer this DZone article.
By using #Lookup.
from Java Doc...
An annotation that indicates 'lookup' methods, to be overridden by the
container to redirect them back to the BeanFactory for a getBean call.
This is essentially an annotation-based version of the XML
lookup-method attribute, resulting in the same runtime arrangement.
Since:
4.1
#Component
public class MyClass1 {
doSomething() {
myClass2();
}
//I want this method to return MyClass2 prototype
#Lookup
public MyClass2 myClass2(){
return null; // No need to declare this method as "abstract" method as
//we were doing with earlier versions of Spring & <lookup-method> xml version.
//Spring will treat this method as abstract method and spring itself will provide implementation for this method dynamically.
}
}
The above example will create new myClass2 instance each time.
2. Using Provider from Java EE (Dependency Injection for Java (JSR 330)).
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
#Component
public static class SomeRequest {}
#Service
public static class SomeService {
#Autowired
javax.inject.Provider<SomeRequest> someRequestProvider;
SomeRequest doSomething() {
return someRequestProvider.get();
}
}
The above example will create new SomeRequest instance each time.
I have an application initializer class that is used to insert application specific data to database.
#Component("applicationInitializer")
public class ApplicationInitializer {
#PostConstruct
public void init(){
// some clever code here
}
}
There is also DevApplicationInitializer class that is used to initialize database with some sample data on developer machine (this class is excluded when deploying production code).
#Component("applicationInitializer")
#Primary
public class DevApplicationInitializer extends ApplicationInitializer {
#PostConstruct
#Override
public void init(){
super.init();
// even more clever code here
}
}
Until I have given a name for the beans (only the #Component annotations) - everything worked fine - when DevApplicationInitializer was available, it was instantiated instead of ApplicationInitializer. When I gave them an applicationInitializer name, the exception is being thrown:
org.springframework.context.annotation.ConflictingBeanDefinitionException:
Annotation-specified bean name 'applicationInitializer' for bean class
[com.example.DevApplicationInitializer] conflicts with existing, non-compatible
bean definition of same name and class [com.example.ApplicationInitializer]
Why the #Primary annotation is not respected when beans have name? I need them to have one, because I ensure in other place that the initializer has been instantiated with #DependsOn("applicationInitializer") annotation.
#Primary has no relation to bean names. The javadoc states
Indicates that a bean should be given preference when multiple
candidates are qualified to autowire a single-valued dependency.
This only applies to a context containing two beans of some type A where a bean of type B requires an A to be injected. The A bean annotated with #Primary will have priority.
Bean ids/names for a given type must be unique. (Bean definitions with the same name can overwrite each other for the same bean type. For example, this would happen if you component scanned a class annotated with #Component but also provided a #Bean method for that same type.)