为什么 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 对这些额外步骤执行的操作。
提前致谢!
我有两个接口 - Singer
和 Instrument
。以及它们的两个实现 - GuitarSinger.class
和 Guitar.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
但是如果我添加这两个步骤之一(仅对其中一个有效),它将正常工作并打印结果。
将@DependsOn("checkedGuitar")
添加到GuitarSinger
:
@Service
@Lazy
@DependsOn("checkedGuitar")
public class GuitarSinger implements Singer {
再添加一行 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
你能帮我理解这个问题吗?为什么它适用于 @DependsOn
或 getBean()
?
它说它找不到任何实现接口的 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, ...
我尝试将 ProxyFactoryBean
与 @Autowired
一起使用,但它在 setInstrument
方法中抛出异常。
问题 - 为什么它与以前调用的 getBean
方法或 @DependsOn
一起工作?我正在尝试了解 Spring 对这些额外步骤执行的操作。
提前致谢!
我有两个接口 - Singer
和 Instrument
。以及它们的两个实现 - GuitarSinger.class
和 Guitar.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
但是如果我添加这两个步骤之一(仅对其中一个有效),它将正常工作并打印结果。
将
@DependsOn("checkedGuitar")
添加到GuitarSinger
:@Service @Lazy @DependsOn("checkedGuitar") public class GuitarSinger implements Singer {
再添加一行
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
你能帮我理解这个问题吗?为什么它适用于 @DependsOn
或 getBean()
?
它说它找不到任何实现接口的 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, ...