为什么 ProxyFactoryBean 使用 @Autowired 抛出 "No qualifying bean of type"?并且不会抛出 pre-getBean()?

Why does ProxyFactoryBean throw "No qualifying bean of type" with @Autowired? And doesn't throw with pre-getBean()?

我尝试将 ProxyFactoryBean@Autowired 一起使用,但它在 setInstrument 方法中抛出异常。

问题 - 为什么它与以前调用的 getBean 方法或 @DependsOn 一起工作?我正在尝试了解 Spring 对这些额外步骤执行的操作。

提前致谢!

我有两个接口 - SingerInstrument。以及它们的两个实现 - GuitarSinger.classGuitar.class.

public interface Singer {
    void singSong();
    Instrument getInstrument();
}
@Service
@Lazy
public class GuitarSinger implements Singer {
    private Instrument guitar;

    @Autowired
    public void setInstrument(Instrument instrument) {
        this.guitar = instrument;
    }

    @Override
    public Instrument getInstrument() {
        return guitar;
    }

    @Override
    public void singSong() {
        System.out.println("I'm singing a song");
        guitar.play();
    }
}
public interface Instrument {
    void play();
}
public class Guitar implements Instrument {
    @Override
    public void play() {
        System.out.println("I'm a guitar!");
    }
}

此接口用于代理介绍:

public interface GuitarChecker {
    boolean isGuitarOk();
}

这个 mix-in class 实现了我们要引入代理的接口:

public class GuitarCheckerMixin extends DelegatingIntroductionInterceptor implements GuitarChecker {
    @Override
    public boolean isGuitarOk() {
        System.out.println("I don't know how to check the guitar");
        return true;
    }
}

最终,配置 class 与 main 方法:

@Configuration
@ComponentScan("com.annotation.test")
public class Config {
    @Bean
    public ProxyFactoryBean checkedGuitar() {
        ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
        Instrument guitar = new Guitar();
        proxyFactoryBean.setTarget(guitar);
        proxyFactoryBean.addAdvisor(new DefaultIntroductionAdvisor(new GuitarCheckerMixin()));
        proxyFactoryBean.setProxyTargetClass(true);
        return proxyFactoryBean;
    }

    public static void main(String[] args) {
        AnnotationConfigApplicationContext appContext
                = new AnnotationConfigApplicationContext(Config.class);
        Singer singer = appContext.getBean(Singer.class);
        singer.singSong();
        Instrument instrument = singer.getInstrument();
        GuitarChecker guitarChecker = (GuitarChecker) instrument;
        guitarChecker.isGuitarOk();
    }
}

如果我运行main,我会得到:

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.annotation.test.Instrument' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1790)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1346)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1300)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.resolveMethodArguments(AutowiredAnnotationBeanPostProcessor.java:759)
    ... 17 more

但是如果我添加这两个步骤之一(仅对其中一个有效),它将正常工作并打印结果。

  1. @DependsOn("checkedGuitar")添加到GuitarSinger:

     @Service
     @Lazy
     @DependsOn("checkedGuitar")
     public class GuitarSinger implements Singer {
    
  2. 再添加一行 appContext.getBean("checkedGuitar")main

     public static void main(String[] args) {
         AnnotationConfigApplicationContext appContext
             = new AnnotationConfigApplicationContext(Config.class);
         appContext.getBean("checkedGuitar");
         Singer singer = appContext.getBean(Singer.class);
         singer.singSong();
         Instrument instrument = singer.getInstrument();
         GuitarChecker guitarChecker = (GuitarChecker) instrument;
         guitarChecker.isGuitarOk();
     }
    

使用这两个更新之一,应用程序将打印以下行:

I'm singing a song
I'm a guitar!
I don't know how to check the guitar

你能帮我理解这个问题吗?为什么它适用于 @DependsOngetBean()

它说它找不到任何实现接口的 Bean Instrument。您实施 Instrument 的唯一 class 是 class Guitar。用 @Component 注释它以便 Spring 可以找到它。

我不是 Spring 用户,所以我不知道代理 bean 工厂和您使用的其他东西是如何被规范地使用的。但是他的呢?

package de.scrum_master.spring.q70623926;

import org.springframework.aop.framework.ProxyFactoryBean;
import org.springframework.aop.support.DefaultIntroductionAdvisor;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("de.scrum_master.spring.q70623926")
public class Config {
  @Bean
  public ProxyFactoryBean checkedGuitar() throws ClassNotFoundException {
    ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
    proxyFactoryBean.setTarget(new Guitar());
    proxyFactoryBean.setProxyTargetClass(true);
    // Make CGLIB proxy implement the same interfaces as the target class
    proxyFactoryBean.setProxyInterfaces(Guitar.class.getInterfaces());
    proxyFactoryBean.addAdvisor(new DefaultIntroductionAdvisor(new GuitarCheckerMixin()));
    return proxyFactoryBean;
  }

  public static void main(String[] args) {
    try (AnnotationConfigApplicationContext appContext = new AnnotationConfigApplicationContext(Config.class)) {
      Singer singer = appContext.getBean(GuitarSinger.class);
      singer.singSong();
      ((GuitarChecker) singer.getInstrument()).isGuitarOk();
    }
  }
}

这产生:

12:39:49.887 ...ProxyFactoryBean - Advice has changed; re-caching singleton instance
12:39:49.887 ...ProxyFactoryBean - Advice has changed; re-caching singleton instance
12:39:49.887 ...ProxyFactoryBean - Advice has changed; re-caching singleton instance
12:39:49.887 ...ProxyFactoryBean - Advice has changed; re-caching singleton instance
12:39:49.887 ...ProxyFactoryBean - Advice has changed; re-caching singleton instance
12:39:49.979 ...DefaultListableBeanFactory - Creating shared instance of singleton bean 'guitarSinger'
I'm singing a song
I'm a guitar!
I don't know how to check the guitar
12:39:50.023 ...AnnotationConfigApplicationContext - Closing ...AnnotationConfigApplicationContext@61baa894, ...