Issue Details (XML | Word | Printable)

Key: SPR-3845
Type: Improvement Improvement
Status: Resolved Resolved
Resolution: Fixed
Priority: Minor Minor
Assignee: Mark Fisher
Reporter: Marc Ludwig
Votes: 0
Watchers: 2
Operations

If you were logged in you would be able to see more operations.
Spring Framework

Improving component-scan performance through more specific search patterns

Created: 05/Sep/07 05:23 AM   Updated: 27/Sep/07 03:12 PM   Resolved: 05/Sep/07 08:33 AM
Component/s: SpringCORE
Affects Version/s: 2.1 M3
Fix Version/s: 2.1 M4

Time Tracking:
Not Specified

Environment: Windows XP. Standalone application.

Virtual Machine: Sun JVM - 1.5
Platform: Standalone


 Description  « Hide

I've been testing the new features in 2.1 relating to the annotation based configuration and classpath scanning for beans, and have one issue and one potential improvement.

1. Static injection
When defining a bean as "@Component" and specifiying "@Resource" on properties, I have noticed that if the property is static, then this is successully injected into the component when using classpath scanning.
As I have previously found no other way of injecting statics, I wondered if this is intended behaviour?

2. findCandidateComponents
In order to improve performance of the class path scanning, is it possible (or would it be a feasible enhancement) to allow the parameterisation of the package search path used within "findCandidateComponents" in the "ClassPathScanningCandidateComponentProvider". Although base packages can be passed in, further restiction would be helpful for performance.

For example, the current code in findCandidateComponents in ClassPathScanningCandidateComponentProvider is:
[code]
String packageSearchPath =
"classpath*:" + ClassUtils.convertClassNameToResourcePath(basePackage) + "/*/.class";
[/code]

If, for example, all the components that need to be auto detected, are within a specific package structure, then further restriction of the source path would be helpful. In our source base, the following results in a 70% reduction in application context start up.

[code]
String restrictionPath = "/*/domain//.class";
String packageSearchPath =
"classpath*:" + ClassUtils.convertClassNameToResourcePath(basePackage) + restrictionPath;
[/code]

Thanks



Juergen Hoeller added a comment - 05/Sep/07 06:47 AM

Thanks for pointing this out! The problem with static injection was simply that we didn't check for static fields and methods there... neither for @Resource nor for @Autowired or @PersistenceContext. I have added explicit checks there now, throwing an exception if such an annotation is found on a static field/method. This will already be available in the next 2.1 M4 snapshot.

Turning this issue into an enhancement request for improving component-scan's performance now, assigning it to Mark.

Juergen


Marc Ludwig added a comment - 05/Sep/07 06:52 AM

Regarding point 1, I was actually considering using this to inject statics. Will this be switchable within 2.1 M4 or is there any other method of achieving this?
Thanks


Mark Fisher added a comment - 05/Sep/07 08:33 AM

The scanner now accepts a 'resourcePattern' that is appended to each base package when scanning. The default value is "*/.class".

This pattern can be provided via xml with the new 'resource-pattern' attribute of the 'component-scan' element.


Marc Ludwig added a comment - 05/Sep/07 08:37 AM

Brilliant!
But, can I raise the question regarding static injection.


Marc Ludwig added a comment - 05/Sep/07 09:11 AM

Wouild really appreciate a comment on this, as I was just about to use the component scan Static injection (side-affect) within a live project.
If this was be better discussed within a different medium, or further info is needed please let me know.
Many Thanks


Paul Benedict added a comment - 05/Sep/07 10:37 AM

IMO, injection is about setting bean instance behavior, not class behavior. However, I'd like to hear an opposing point of view.


Marc Ludwig added a comment - 05/Sep/07 11:03 AM

Not sure whether my view is opposing. Really it's just been driven by the requirements of the Domain, and an attempt to keep the code simple.
We wanted to add further behaviour to our Domain Objects so therefore an Aggregate Root (complex/large) DO has a relationship with a static Repository.
Therefore, when we want to find an Aggegate Root Object from the presentation layer or web service endoint etc, we do:

AggregateRootDO.findby(someID);

In this way we don't need to instantiate an object, prior to finding one.

Within the AggregateRootDO, the static findby method references the static instance of the Repository interface.

Currently we have to retrive this from the Context Application as we can not inject the static, which has the detremental effect of making the Domain Objects dependant upon some framework code.

The static injection through Spring using the component scanning and @Component, was attractive so that we could remove this dependency.

Marc


Juergen Hoeller added a comment - 05/Sep/07 05:05 PM

Technically, what you're doing there is creating an instance of your AggregateRootDO class (it is autodetected through the @Component annotation and turned into a singleton bean instance), injecting that singleton instance and then offering static accessors on that AggregateRootDO class. Exposing static configuration state in that way isn't incredibly clean architecturally; that said, I agree that it may be quite convenient in some scenarios.

For that arrangement to work, simply let your AggregateRootDO class have non-static setter methods with an @Resource or @Autowired annotation. Those setter methods can then in turn store their passed-in object in a static field, with the static accessor methods obtaining the reference from that field. So the configuration actually still happens on an instance (with the annotations sitting on instance methods), just with the class offering a static accessor.

The conceptual problem here is that annotation-driven injection happens for each bean instance. So we shouldn't inject static fields or static methods there because that would happen for every instance of that class. The injection lifecycle is tied to the instance lifecycle, not to the class lifecycle. Bridging between an instance's state and static accessor - if really desired - is up to the concrete bean implementation but arguably shouldn't be done by the framework itself.

Juergen


Marc Ludwig added a comment - 06/Sep/07 02:07 AM

Thanks so much for the infmormative reply, which has served to fully explain the underlying conceptual and archictectural issues.
Also, thanks for the earlier fix.
Regards


Leonardo Pinho added a comment - 27/Sep/07 11:47 AM

Mark, could you update the new xsd at http://www.springframework.org/schema/context/spring-context-2.1.xsd, please?

Thanks!
Leonardo


Mark Fisher added a comment - 27/Sep/07 03:00 PM

Leonardo,

I have updated all of the 2.1 schemas at springframework.org to the 2.1-M4 release versions. Note that 2.5 versions are now available as well. If you are using nightly builds, you can point to 2.5 instead (since 2.5 has superseded 2.1).

Mark


Leonardo Pinho added a comment - 27/Sep/07 03:12 PM

Thank you very much!

Leonardo