[JAVA] A story about BeanNotOfRequiredTypeException occurring after applying AOP in Spring

Operating environment

How the exception occurred

The code that actually caused the exception cannot be published, so let's take the Todo application introduced in the TERASOLUNA guidelines as an example: sweat :.

--Create a class that implements MethodInterceptor under the domain package.

SampleInterceptor.java


package todo.domain.interceptor;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SampleInterceptor implements MethodInterceptor {

  private static final Logger logger = LoggerFactory.getLogger(SampleInterceptor.class);

  @Override
  public Object invoke(MethodInvocation invocation) throws Throwable {
    //Just log output before executing the target method
    logger.info("Interceptor called.");
    return invocation.proceed();
  }
}

--Apply ʻInterceptorcreated in ↑ toTodoServiceImpl` in the AOP setting in todo-domain.xml.

todo-domain.xml


  <aop:config>
    <aop:pointcut id="sample" expression="execution(* todo.domain.service.todo.TodoServiceImpl.*(..))" />
    <aop:advisor advice-ref="resultMessagesLoggingInterceptor" pointcut="@within(org.springframework.stereotype.Service)" />← The original one
    <aop:advisor pointcut-ref="sample" advice-ref="sampleAdvice" order="-1" />
  </aop:config>

  <bean id="sampleAdvice" class="todo.domain.interceptor.SampleInterceptor" />

--Change the Service class that is ʻInject in TodoCotrollertoTodoServiceImpl`.

TodoController.java


@Controller
@RequestMapping("todo")
public class TodoController {
  @Inject
  TodoServiceImpl todoService;

So, when I run this Todo application, I get the following exception at startup.

Caused by: org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'todoServiceImpl' is expected to be of type 'todo.domain.service.todo.TodoServiceImpl' but was actually of type 'com.sun.proxy.$Proxy32'
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.checkBeanNotOfRequiredType(DefaultListableBeanFactory.java:1491)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.checkBeanNotOfRequiredType(DefaultListableBeanFactory.java:1498)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1470)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1102):rolling_eyes:
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1064)
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585)
	... 42 more

I'm assuming the TodoServiceImpl type, but it seems that it is actually defined as the com.sun.proxy. $ Proxy32 type: scream :.

The reason is the difference in the mechanism for proxying

Spring provides two mechanisms for applying AOP.

  1. JDK DynamicProxy
  2. CGLib

This difference is according to Understanding how to implement common request processing on Spring MVC (+ Spring Boot). It's like implementing an interface. In this example, since the interface is implemented, I used JDK DynamicProxy to proxy it, but it seems that an exception occurred because I tried to ʻInject the implementation class TodoServiceImplwithTodoContorller. .. In this case, in order to ʻInject the implementation class, it is necessary to proxy it using the mechanism of CGLib, and the setting is to set the proxy-target-class attribute of the config element of AOP to true. I will. (The default is false.)

todo-domain.xml


 <aop:config proxy-target-class="true">

The above setting forces the proxy conversion mechanism to CGLib, and if the class does not originally have an interface, it will be automatically proxyed by the CGLib mechanism.

By the way, please note that Spring AOP does not apply to classes that are not registered in the DI container **.

How did you come to post this article?

As a memo because it actually occurred in the system developed in business: stuck_out_tongue :.

Other reference articles / pages

-Differences in proxies target classes between Spring AOP and libraries

-Spring AOP documentation

Recommended Posts

A story about BeanNotOfRequiredTypeException occurring after applying AOP in Spring
About Spring AOP
About spring AOP
A story about a Spring Boot project written in Java that supports Kotlin
A story about the JDK in the Java 11 era
About Spring AOP Pointcut
A story about making Spring + Hibernate + MySQL apps replication compatible
About binding of Spring AOP Annotation
A little troublesome story in Groovy
Create a Spring Boot project in intellij and exit immediately after launching
A story about converting character codes from UTF-8 to Shift-jis in Ruby
A story about an arithmetic overflow that you shouldn't encounter in Ruby
About returning a reference in a Java Getter
[Creating] A memorandum about coding in Java
A story about saving an image with carrierwave in a nested form using a form object.
A story about a super beginner participating in the AtCoder contest for the first time (AtCoder Beginner Contest 140)