0
votes

I'm trying to understand Spring proxy mechanism and I have problem with one thing. I have Interface:

public interface MyInterface{
  void myMethod();
}

and implementing class:

@Component
public class MyBean implements MyInterface{
  @Override
  public void myMethod(){
    //do something
  }
}

Now I create Aspect, for example:

@Aspect
@Component
public class LogAspect {
    @Before("execution(public * *(..))")
    public void logBefore() {
        System.out.println("Before aspect");
    }
}

And I have simple starter class:

@Configuration
@ComponentScan
@EnableAspectJAutoProxy
public class SpringAopApplication {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(
                SpringAopApplication.class);

        MyBean bean = ctx.getBean(MyBean.class);
//      MyInterface bean = ctx.getBean(MyInterface.class); //works
        bean.myMethod();

        ctx.close();
    }
}

According to the Spring docs we can read:

If the target object to be proxied implements at least one interface then a JDK dynamic proxy will be used. All of the interfaces implemented by the target type will be proxied. If the target object does not implement any interfaces then a CGLIB proxy will be created.

But I got an error No qualifying bean of type [MyBean] is defined. It works only when I enable CGLib proxying by @EnableAspectJAutoProxy(proxyTargetClass = true). Can someone explain what I am missing here? Why MyBean is not discovered when using AOP? ctx.getBean(MyInterface.class) works, but I can't imagine the situation with many implementations of such interface.

2

2 Answers

3
votes

The target object to be proxied (MyBean) implements at least one interface (MyInterface), so a JDK proxy is used. This proxy implements MyInterface, but is NOT an instance of MyBean. Thats why

MyInterface bean = ctx.getBean(MyInterface.class);

works and

MyBean bean = ctx.getBean(MyBean.class);

not.

CGLib proxies are created by subclassing the target object, so the bean created is a subclass of MyBean and implements MyInterface. In this case also

MyBean bean = ctx.getBean(MyBean.class);

works.

...but I can't imagine the situation with many implementations of such interface.

The only reason for MyInterface could be, to allow spring to create a JDK proxy, so there is no need to have many implementations.

0
votes

Because if you check up your bean class you'll find com.sun.proxy.$Proxy21 (or something similar) instead, which wraps your method. They are incompatible types even they have the same interface. For example:

public interface AnInterface {
   void func();
}

public class Bb implements AnInterface{
   @Override
   public void func() {
      System.out.println("bb");
   }
}

public class Cc implements AnInterface{
@Override
   public void func() {
      System.out.println("cc");
   }
}

So when you call

public static void main(String[] args) {
    Bb b = new Bb();
    Cc c=b; // Error
    AnInterface c=b; // Ok
}