I'm trying to understand how much time component scanning is adding application context creation. Currently, it takes ~100 seconds to create the application context and I suspect that component scanning for component definitions is costly. I have a series of questions as follows:
How do I measure the total time spent component scanning?
Does the number of base context:component-scan entries impact the search space, I'm assuming component scanning uses PathMatchingResourcePatternResolver to scan each entry on the classpath and then finding classes that match the base-package regex. Is it more efficient to structure the metadata like:
<context:component-scan base-package="foo" />
<context:component-scan base-package="bar" />
<context:component-scan base-package="baz" />
or
<context:component-scan base-package="foo, bar, baz" />
I'm also assuming that the number of classes that PathMatchingResourcePatternResolver influences component scanning as the check for corresponding component annotations requires the class file to be inspected. So is it good practice to only keep classes with annotations in a well-defined package to reduce the number classes to inspect?
Is there known best practices listed somewhere on what considerations to make in the design to get the most optimal component scanning performance?
Auto scan classes requires to scan all classes in the specified package(s) and can take a long time. If in your package almost all classes are defined as Bean then can use single component scan.
If there are some packages where classes are defined as Bean, then definitely multiple component scan of only that packages should define to reduce the auto scan time.
<context:component-scan base-package="foo" />
<context:component-scan base-package="bar" />
<context:component-scan base-package="baz" />
Else all beans define in spring configuration instead of Auto scan, but it can increase large size of your file.
Related
Description
The general use case scenario is - in the world of application package dependency graph, we want to have a collection in parent package and we want to make it available for all children packages to add elements to the list, in other words, extending the list for higher level execution in the parent package.
The goal is let downstream applications able to inject elements to this higher level applications predefined collection so that we achieve federated model for elements while keeping overall execution control in the parent application package.
Example
Say we have 2 application packages
- parent package
- child/children package(s)
The children packages child listed parent package as build dependency
In parent package's spring configuration xml, we have a list that need to be injected with instances of a class really.fun.processor
<util:list id="myProcessors" value-type="really.fun.processor" />
If we host the classes and their instances (beans) in the child package (such as below beans), is it possible to inject back to the parent's list?
<bean name="funProcessor1" class="really.fun.processor"/>
<bean name="funProcessor2" class="really.fun.processor"/>
...
<bean name="funProcessorN" class="really.fun.processor"/>
Question
Is this possible in Spring? If so, what's recommended approaches for this use case?
Figured out the solution:
ComponentScan https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/ComponentScan.html
EnableAutoConfiguration https://docs.spring.io/spring-boot/docs/1.3.8.RELEASE/reference/html/using-boot-auto-configuration.html
Both are designed to solve the above use case very nicely.
in xml based approach, we configure the bean definition in xml ,
beans will be created in the order we have defined the beans.
1) <beans>
<bean id="a" class="com.abc.a"/>
`<bean id="b" class="com.abc.b"/>`
</beans>
Here , a will be created first before b.
2)<beans>
<bean id="a" class="com.abc.a">
<property name="c" ref="c"/>
</bean>
<bean id="b" class="com.abc.b/">
<bean id="c" class="com.abc.c/">
here c will be created first, then a then b.
In case of annotation driven approach, how to control the sequence of object creation? using ordered interface ?
Spring container creates the dependent objects (because they are needed by the main objects as per the object graph) first both in xml & annotation approach.
In case of annotation driven approach, how to control the sequence of object creation? using ordered interface ?
You can't control the order of objects as the dependent objects are always needed to be created first and then followed by the main objects.
The order interface is for a different purpose which is to push the objects into a list using autowired.
You can refer the example in the below link for using #Order to set/push an object into a list:
What is the use of #Order annotation in Spring?
Spring has an Order attribute of java config and an order attribute for xml configuration to control the order in which beans are created. (Lower values means earlyer creation, negative number are allowed too)
An other way is to control the order is DependsOn annotation/attribute.
I am using component scan to scan all the Controller,Service and DAO classes. If I put my Services and DAO interfaces on the same package with the implementer, would this cause the component scan process slower (Would it be like two times slower) ? Does it scan the subpackages as well ?
Yes, it will be slower. However you should not consider this as a factor when designing your package layout. Let the architecture drive placement of classes, not some arbitrary framework requirements and peculiarities.
Also you can filter out some classes/patterns if your application is really huge and you want to cut down the bootstrap time (see 4.10.3 Using filters to customize scanning):
<context:component-scan base-package="org.example">
<context:include-filter type="regex" expression=".*Stub.*Repository"/>
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Repository"/>
</context:component-scan>
And yes, it does scan subpackages.
Wondering if there is a way to dynamically instantiate beans based on set of values in your property file using PropertyPlaceholderConfigurer class.
I have a java bean say Student with two attributes: "name" and "subject"
I have a property file with:
student.1.name=student1name
student.1.subject=student1subject
student.2.name=student2name
student.2.name=student2subject
Now I have a Classroom object that can take a list of students.
I am wondering if there is a way we could do this using Spring. The challenge here is that the number of students could vary.
If there was only one student object then:
<bean id="student" class="com.abc.Student">
<property name="name" value="${student.1.name}" />
<property name="subject"
value="${student.1.subject}" />
</bean>
<bean id="classRoom" class="com.abc.ClassRoom">
<property name="student" ref="student" />
</bean>
would have worked. But in this case we have a list of n Students. And the value of n could vary depending on the number of entries in the properties file.
I'm with Kevin--IMO you're going about this the wrong way.
One possible workaround would be to create a bean that takes the property file as an argument, reads it in, and exposes a list of students (which would need to be indexed on something, like the n in the existing property file).
The classroom bean could then use that list of students.
But it sure looks like you're trying to duplicate the functionality of a DB, without a DB, in an awkward way.
I don't think there's a way to do that with PropertyPlaceholderConfigurer. Usually when I have a situation like that I choose a configuration format of either JSON or XML and use GSON/Jackson/JAXB to unmarshall the data into objects.
first off I point to the similar question. I spent more than an hour to set this up, but PathMatchingResourcePatternResolver still scans everything.
I have one common.xml (that is imported from specific.xml) and a specific.xml bean definition file. The context is loaded from specific.xml. In common.xml there is this element:
<context:component-scan base-package="cz.instance.transl">
<context:exclude-filter type="aspectj"
expression="cz.instance.transl.model..* && cz.instance.transl.service..* && cz.instance.transl.hooks..*"/>
</context:component-scan>
Where classes in packages like cz.instance.transl.service.* should not be subject of scanning, but everything else in here cz.instance.transl.* should be scanned through. But PathMatchingResourcePatternResolver marks everything as matching resources. It is the same with regex.
EDITED: If I declare context:component-scan in specific.xml, then the scanning doesn't even start, and I get NoSuchBeanDefinitionException on annotation based dependencies in common.xml.
BTW: in xml style configuration, one can have many components that share a common.xml beans via "import resource" when loading context. How this is done when Annotation-based container configuration is used ?
In this case you need "or" rather than "and":
<context:exclude-filter type="aspectj"
expression="cz.instance.transl.model..* || cz.instance.transl.service..* || cz.instance.transl.hooks..*"/>