Anyone can explain how Spring defines the bean creation mechanism when create a bean which depends on a list of other beans? It would be good to show the part of Spring specification on how it's defined.
Code like:
public interface Test {
}
#Service
public class TestImpl1 implements Test{
}
#Service
public class TestImpl2 implements Test{
}
public class TestContainer {
List<Test> testList;
TestContainer() {
testList = new ArrayList<>();
}
public void addTest(Test test) {
testList.add(test);
}
}
then
#Bean
public TestContainer testContainer(List<Test> testList) {
TestContainer testContainer = new TestContainer();
for (Test test : testList) {
testContainer.addTest(test);
}
return testContainer;
}
Question is really: when creating bean for TestContainer, how does Spring figure out what should be in List testList?
This looks like what you are looking for:
https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-factory-class
You haven't specified what exactly do you want to know about bean creation but here is the minimum you should know. By default all beans are singleton scoped (only created once during the container life-cycle and for all the subsequent request the same instance is returned). All singleton scoped beans are created eagerly. If the singleton bean is dependent on some other beans (needs them for instantiation) then those other beans will be instantiated with it/right before it, doesn't matter whether they are singletons or not, marked as lazy or not.
This is part of the spring documentation I think on their website. Look for it. The whole spring documentation is worth to read, even if it is a long read (https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#spring-core)
But mostly, spring would first read all the XML, anotations and other source of config data and get a list of beans to init. Then it would get a list of dependencies between beans constructing kind of a tree. As the dependencies need to be initialized first, there an obvious orderining for initialization.
On top, you can set your own priorities for beans so that you can get some beans initialized first or last for example.
For your specific case, spring will inspect the code source as well as use the Java reflection API to figure out you want a collection of interface Test implementations. So spring would look for ALL the defined bean that match and return them that not more complex than that.
It's mostly using the concepts of graph data structure where the beans become the nodes of the graph and they are resolved using topological sort.
Related
I am trying to understand what would be the correct usage of Spring prototype bean.
May be the following code sample will help in you understanding my dilemma:
List<ClassA> caList = new ArrayList<ClassA>();
for (String name : nameList) {
ClassA ca = new ClassA();
//or Shall I use protypebean, using method lookup I can inject the dependency of ClassA.
// ClassA ca = getPrototypeClassA();
ca.setName(name);
caList.add(ca);
}
So my exact point is in this scenario shall I go with method injection or new() operator.
Provide your view with justification.
You can make use of either of the ways, because ultimately client code is responsible for handling the life-cycle of the prototype bean rather than spring container.
According to Spring-docs,
In some respects, you can think of the Spring containers role when
talking about a prototype-scoped bean as somewhat of a replacement for
the Java 'new' operator. All lifecycle aspects past that point have to
be handled by the client.
Spring does not manage the complete lifecycle of a prototype bean: the
container instantiates, configures, decorates and otherwise assembles
a prototype object, hands it to the client and then has no further
knowledge of that prototype instance. It is the responsibility of the
client code to clean up prototype scoped objects and release any
expensive resources that the prototype bean(s) are holding onto.
If ClassA needs to have #Autowired references, then go for a prototype bean.
Otherwise a simple POJO (that the Spring container is unaware of) will do.
It seems that your instance need some runtime values in order to initialise properly. In such case ,it depends on if you need to use spring feature such as AOP for the ClassA instance. If yes , go with the method injection .If not , you can consider using factory pattern . Much more OO and cleaner to me :
Something like the following . You should get the idea.
#Component
public class FactoryForClassA {
#Autowired
private FooBean someDependencyForClassA;
public ClassA create(String name){
ClassA a = new ClassA(someDependencyForClassA);
a.setName(name);
return a;
}
}
And the client code:
#Autowired
private FactoryForClassA factoryForClassA;
List<ClassA> caList = new ArrayList<ClassA>();
for (String name : nameList) {
ClassA a = factoryForClassA.create(name);
caList.add(ca);
}
(spring boot 1.5, java 8)
Suppose there is a Foundation, some Wall types, and Ceilings. They depend on each other, just like their physical counterparts.
This configuration class has a Foundation injected and creates Wall beans, so that Ceilings can have Walls injected. Don't mind the bad practices, I'm just trying to keep the code as short as possible without changing the essential mechanisms.
#Configuration
class Config {
#Autowired
Foundation foundation;
#Bean
// assume there is a lot of repetitive logic here
WoodenWall wood() { return new WoodenWall(foundation); }
#Bean
BrickWall brick() { return new BrickWall(foundation); }
}
And a ceiling:
#Component
class KitchenCeiling {
#Autowired
WoodWall wall;
}
I'm going to be making a lot more Wall types and want them all registered as beans. Instead of having to define a #Bean method for each and every one of them, I want to instantiate them all in a loop and register them manually in a single go. Think of an AllTypesOfWallsBeanFactory if you wish.
#Configuration
class Config implements ??? {
#Autowired
Foundation foundation;
#Override
void addBeans(??? beanRegistry) {
for (Class beanClass : wallClasses) {
// instantiate BrickWall, WoodWall, etc
registry.add(beanClass.getSimpleName(), beanClass, wallInstance);
}
}
}
The problem is, I can't find the right interface to implement or the right SpringBeanRegistryPostProcessorFactoryImplementationThingamajig to go to. I've tried the answers given on all the other SO posts I could find but none do the right thing.
One issue here is that I need the context to already be initializing beans since I need a Foundation, but I also want to add some more beans to the context so that Ceilings yet to be initialized can inject my freshly made Walls.
#Bean methods do exactly that: they can take dependencies that are already initialized and return new beans to be used elsewhere at the same time. I just need the programmatic equivalent to this exact mechanism.
I know dependency resolution is harder in this situation (since there isn't any reflective information for spring to figure out the total following order), but it's gotta be possible to tell spring to
initialize what it has dependencies for
process the newly created beans
goto 1
BeanDefinition doesn't fit the bill because it doesn't take any instances, and to use the factoryMethod setting I would need to make a factory class for each Wall. Back to square one.
Most of the BeanDefinitionRegistryPostProcessor et al interfaces are called too late, don't inject the beans I give them into dependent beans (there was 1 that took instances but didn't do anything with them), or demand a default constructor (i.e. no dependencies). They also tend to give you objects that only take BeanDefinition.
In another project where there was a similar need, what ended up being used was a factory method with still a #Bean method for each instance it needed to produce. I'm starting to think it isn't really possible and what was done in this project is as good as it'll get.
You can try using #PostConstructwith ConfigurableApplicationContext
#Configuration
class Config {
#Autowired
Foundation foundation;
#Autowired
ConfigurableApplicationContext ctx;
#PostConstruct
void addBeans() {
for (Class beanClass : wallClasses) {
ctx.getBeanFactory().registerSingleton(beanClass.getSimpleName(), beanClass, wallInstance);
}
}
}
I'm going to conclude that it just isn't possible to do this reliably. The best one can do is making a factory method and a #Bean method calling the factory for each bean instance that needs to be registered. It doesn't seem possible to cut the #Bean methods out of the picture.
I am looking into a codebase where every POJO has been managed by spring and injected using lookup annotation.
#Lookup
public Publisher getPublisher() {
return new Publisher();
}
#Lookup
public Book getBook() {
return new Book();
}
These Publisher and Book objects are nothing but POJO with just getter/setters. These classes are spring managed as prototype beans. I am thinking, it is over use of lookup annotation and overhead where we could just use factory methods or simply create new instance. Do you think using lookup annotation for this use case useful/efficient?
In a general way, making instances of a class some spring beans is not relevant if these beans never be needed to take advantage of Spring features and if these beans never be injected in other beans or never needs to inject other beans in their own instance.
#Lookup is the annotation-based way of the the old XML lookup-method attribute. Besides beans created with this annotation also have multiple limitations. For new projects I never use it.
As alternative as you need to declare beans in the java class the #Bean annotation that creates "not limited" beans should generally be favored instead of.
EDIT :
I wrote an answer to a very related question yesterday : Spring - is using new a bad practice?.
I just updated it to be more exhaustive.
Need some help in spring here.
In our project we use XML and annotation configurations (Spring 4.1)
Recently I've faced the following task:
I have a list of beans of scope prototype, all of them implement the same interface.
In addition I have one singleton bean that has execute method. Inside the method the bean should access the list of those prototype beans.
Every time the 'execute' method gets executed I would like to get the access to the different instances of those prototype beans).
In singleton I don't have the whole list of beans known in advance, so I just #Autowire the whole collection so that every bean implementation known in the application context will be loaded.
interface SomeInterface {
}
class PrototypeBean1 implements SomeInterface {
...
}
class PrototypeBean2 implements SomeInterface {
...
}
class MySingletonBean {
#Autowire (????)
List<SomeInterface> allPrototypeBeansLoadedIntoTheApplicationContext;
public void execute() {
// this one is called many times,
// so I would like to get different lists of
//"allPrototypeBeansLoadedIntoTheApplicationContext"
// with different actuals bean upon every invocation
// how do I achieve this???
}
}
So my question is: What is the most clean way to achieve this? Ideally I would like to get a solution totally decoupled from spring interfaces (like injecting ApplicationContext/BeanFactory stuff)
I don't mind to use Aop here (performance is not that critical), but I can't really wrap my head around a clean spring solution. So any help will be appreciated.
Thanks in advance
I have been trying to achieve similar goal with Spring and after reading Spring docs using either ServiceLocatorFactoryBean or method injection (with #Lookup) came up and looked promising.
However after tried both approach results turned out to be frustrating. Neither way supports returning beans in List. And I got this exception:
No qualifying bean of type 'java.util.List' available
Apparently Spring treated the return type as a regular Object.
So eventually my solution became creating a new object to wrap the list as return type.
#Component
#Scope("prototype")
public class ProcessorList
{
private List<Processor> processors;
public ProcessorList(List<Processor> processors)
{
this.processors = processors;
}
public List<Processor> getProcessors()
{
return processors;
}
public void setProcessors(List<ChangeSetProcessor> processors)
{
this.processors = processors;
}
}
then create a Factory class for the List Object:
#Component
public interface ProcessorFactory
{
ProcessorList getProcessorList();
}
Then use ServiceLocatorFactoryBean to register the factory:
#Configuration
public class MyConfiguration{
#Bean
public FactoryBean serviceLocatorFactoryBean()
{
ServiceLocatorFactoryBean factoryBean = new ServiceLocatorFactoryBean();
factoryBean.setServiceLocatorInterface(ProcessorFactory.class);
return factoryBean;
}
}
Finally implement the interface and make sure mark them all with #Scope("prototype")
Now you'll get new instance each time you use the factory method!
It's similar to use method injection if you prefer.
I'm trying to change some legacy code to use DI with Spring framework. I have a concrete case for which I'm wondering which is the most proper way to implement it.
It is a java desktop application. There is a DataManager interface used to query / change data from the data store. Currently there is only one implementation using a XML file for store, but in the future it is possible to add SQL implementation. Also for unit testing I may need to mock it.
Currently every peace of code that needs the data manager retrieves it by using a factory. Here is the source code of the factory:
public class DataManagerFactory
{
private static DataManagerIfc dataManager;
public static DataManagerIfc getInstance()
{
// Let assume synchronization is not needed
if(dataManager == null)
dataManager = new XMLFileDataManager();
return dataManager;
}
}
Now I see 3 ways to change the application to use DI and Spring.
I. Inject the dependency only in the factory and do not change any other code.
Here is the new code:
public class DataManagerFactory
{
private DataManagerIfc dataManager;
public DataManagerFactory(DataManagerIfc dataManager)
{
this.dataManager = dataManager;
}
public DataManagerIfc getDataManager()
{
return dataManager;
}
public static DataManagerIfc getInstance()
{
return getFactoryInstance().getDataManager();
}
public static DataManagerFactory getFactoryInstance()
{
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {"com/mypackage/SpringConfig.xml"});
return context.getBean(DataManagerFactory.class);
}
}
And the XML with the bean description:
<bean id="dataManagerFactory"
class="com.mypackage.DataManagerFactory">
<constructor-arg ref="xmlFileDataManager"/>
</bean>
<bean id="xmlFileDataManager"
class="com.mypackage.datamanagers.xmlfiledatamanager.XMLFileDataManager">
</bean>
II. Change every class that is using the data manager so it takes it through the constructor and store it as a class variable. Make Spring bean definitions only for the "root" classes from where the chain of creation starts.
III. Same as II. but for every class that is using the data manager create a Spring bean definition and instantiate every such class by using the Spring Ioc container.
As I'm new to the DI concept, I will appreciate every advice what will be the correct and "best practice" solution.
Many thanks in advance.
Use option 3.
The first option keeps your code untestable. You won't be able to easily mock the static factory method so that it returns a mock DataManager.
The second option will force you to have the root classes know all the dependencies of all the non-root classes in order to make the code testable.
The third option really uses dependency injection, where each bean only know about its direct dependencies, and is injected by the DI container.
Well... why did you write the factory in the first place? Spring is not intended to make you change how you write code (not just to suit Spring that is), so keeping the factory is correct as it uses well-known pattern. Injecting the dependency into the factory will retain that behaviour.
Option 3 is the correct route to take. By using such a configuration you can usefully take components of your configuration and use them in new configurations, and everything will work as expected.
As a rule of thumb, I would expect one call to Spring to instantiate the application context and get the top-level bean. I wouldn't expect to make repeated calls to the Spring framework to get multiple beans. Everything should be injected at the correct level to reflect responsibilities etc.
Beware (since you're new to this) that you don't plumb in your data manager into every class available! This is quite a common mistake to make, and if you've not abstracted out and centralised responsibilities sufficiently, you'll find you're configuring classes with lots of managers. When you see you're doing this it's a good time to step back and look at your abstractions and componentisation.