This page looks best with JavaScript enabled

Spring AOP & Bean Naming conflict

 ·  ☕ 4 min read  ·  🏍 Zisis

Spring AOP fun!

My everyday life at work involves dealing with several Java frameworks such as Spring, Hibernate and JSF among others. Most frameworks Take Spring for example. IT removes a lot of burden from the developer and gets you up to speed fast but in order to achieve this it makes a lot of conventions. This is not bad per-se but it can turn into an ugly beast at times - notably for the uninitiated - when trying to decipher what is wrong in your application.

Lately, I’ve been trying to extend the use of Spring AOP in our project and utilize it to measure the performance of our app. A simple google search will return a lot of sample implementations to give you an idea. In essence by using AOP and the @Around advice I managed to get the execution times of most of our service calls. A little bit of extra custom code and we also got the percentages that each part of our app was contributing to the overall time of execution. It’s true that the more you are using Spring the more you appreciate its benefits.

Everything was working just fine and we were all happy until a colleague of mine turned to me saying

“You know, we’ve got to add this service’s methods to the calculations, I think that’s the one that’s slowing us down”

and I thought to myself

“Well, that’s easy, I’ll just add another one aop:pointcut with the corresponding expression and link that to a new aop:around advice”.

In reality it should have been as simple as that but I’ve ended up spending a whole working day to sort it out.

Erroneous behavior

As soon as the pointcut and advice were added errors of the following type started cropping up

1
2
3
4
5
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: 
No matching bean of type [com.mycompany.StupidService] found for dependency: 
expected at least 1 bean which qualifies as autowire candidate for 
this dependency. Dependency annotations: 
{@org.springframework.beans.factory.annotation.Autowired(required=true)}

or

1
2
3
4
5
6
7
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: 
private com.mycompany.StupidService; nested exception is 
org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching 
bean of type [com.mycompany.StupidService] found for dependency: 
expected at least 1 bean which qualifies as autowire candidate for this dependency. 
Dependency annotations: 
{@org.springframework.beans.factory.annotation.Autowired(required=true)}

or

1
2
3
4
Caused by: java.lang.IllegalStateException: Cannot convert value of type 
[org.springframework.aop.aspectj.AspectJExpressionPointcut] to required type 
[com.mycompany.StupidService] for property stupidService: 
no matching editors or conversion strategy found

Digging in

I started an intensive internet search with the above exceptions and although I found a lot of references and provided solutions none of them really fitted my case.

The bean I was injecting was definitely there (StupidServiceImpl.java) and it was definitely implementing the required interface (StupidService.java). Spring uses dynamic JDK proxies by default intercepting interface methods only. Moreover all references inside the code were referring to the interface and not the implementation. Not to mention other services will the same logic (as far as setup is concerned) were successfully injected. I tried everything JDK-proxies, CGILIB proxies, read again and again the Spring AOP documentation but to no avail. I even wrote a BeanFactoryPostProcessor to understand what was happening during Spring initialization and it was then that I realized that StupidService was initialized as an AspectJExpressionPointcut and not as a StupidService instance and reconsidered the meaning behind the above exception.

Solution

What was the case? My StupidServiceImpl bean was annotated as

1
@Service(stupidService)

while my aop:pointcut was declared inside applicationContext.xml as follows

1
<aop:pointcut id=”stupidService” expression=”execution(* com.mycompany.stupidservice.StupidService.*(..))”/>

The id of the Service in the annotation was the same as the pointcut’s ID in the XML but neither Spring nor my IDE gave me an error that 2 Spring “elements” shared the same id. The end result was that StupidService was instantiated as a pointcut (annotations are parsed first, then xml configuration files) and when I was trying to inject it on my beans it could not be converted to a StupidService bean.

Takeaways

Why the hell should someone give the same name to an AOP advice and a bean?
Should Spring provide a more informative message?

  • It seems that while Spring validates between bean ids in annotations and xml files (Spring flags an error if one bean in an XML has the same id with an annotated bean), it does not do so when it comes to annotations and aop advices declared in an XML file.
  • Always make sure that the IDs of your beans are unique.

Usually your IDE will take good care of this job but as it seems this is not always the case. Pay extra attention to the errors displayed. If you see a failure in casting a bean from one type to another maybe you have fallen to the same “trap”.

PS. The above were observed in Spring 3.0.5.RELEASE.

Share on

Zisis Tachtsidis
WRITTEN BY
Zisis
Software Engineer, Husband to one, Father of two, Rider of two (motorcycles)