NoSuchBeanDefinitionException 导致 beans 接口或 bean 上的建议
NoSuchBeanDefinitionException caused either the beans interface or an advice on the bean
正在学习 Spring、运行 一些我无法理解或找不到参考的东西。做了一个简约的项目来过滤掉混乱并使事情更清晰:1 个包 6 个文件,不包括 pom.xml :
1 App.java - 里面是 main() 方法。
package beantest;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.ApplicationContext;
public class App{
public static void main(String[] args){
ApplicationContext context = new AnnotationConfigApplicationContext(JavaConfig.class);
ClassAAA aaa = (ClassAAA) context.getBean(ClassAAA.class);
ClassBBB bbb = (ClassBBB) context.getBean(ClassBBB.class);
aaa.doSomething();
bbb.doSomething();
}
}
2 ClassAAA.java
package beantest;
public class ClassAAA{
public void doSomething(){
System.out.println("running 'doSomething()' by AAA object");
}
}
3 ClassBBB.java - ClassAAA 和 ClassBBB 之间的唯一区别是 BBB 实现了 InterfaceX。
package beantest;
public class ClassBBB implements InterfaceX{
public void doSomething(){
System.out.println("running 'doSomething()' by BBB object");
}
}
4 InterfaceX.java - 没有方法,在这种状态下。
package beantest;
public interface InterfaceX{
//void doSomething();
}
5 JavaConfig.java
package beantest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@EnableAspectJAutoProxy
public class JavaConfig{
@Bean
public ClassAAA aaa(){
return new ClassAAA();
}
@Bean
public ClassBBB bbb(){
return new ClassBBB();
}
@Bean
public Aspect1 aspect1(){
return new Aspect1();
}
}
6 Aspect1.java
package beantest;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class Aspect1{
@Before ("execution(* beantest.ClassAAA.doSomething(..))")
public void beforeAAAdoesSomething(){
System.out.println("##### BEFORE advice on AAA's doSomething() #####");
}
@Before ("execution(* beantest.ClassBBB.doSomething(..))")
public void beforeBBBdoesSomething(){
System.out.println("##### BEFORE advice on BBB's doSomething() #####");
}
}
*** 运行 这给出了预期的输出:
##### BEFORE advice on AAA's doSomething() #####
running 'doSomething()' by AAA object
##### BEFORE advice on BBB's doSomething() #####
running 'doSomething()' by BBB object
*** 取消注释 InterfaceX.java 和 运行 中的“doSomething”方法给出以下输出:
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'beantest.ClassBBB' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:353)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:340)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1093)
at beantest.App.main(App.java:12)
为什么 运行 作为接口实现的方法会阻止 Spring 在从未在任何地方提及所述接口的情况下找到 bean?
如果从这里我要注释掉 Aspect1.java 中关于 ClassBBB
的建议
//@Before ("execution(* beantest.ClassBBB.doSomething(..))")
没有抛出异常,输出符合预期:
##### BEFORE advice on AAA's doSomething() #####
running 'doSomething()' by AAA object
running 'doSomething()' by BBB object
最后,改变
ClassBBB bbb = (ClassBBB) context.getBean(ClassBBB.class);
至
InterfaceX bbb = (InterfaceX) context.getBean(InterfaceX.class);
解决了未注释的建议和接口方法的问题。
我什么时候应该通过 class 查找实现接口的 bean?实验的时候无意中发现了这个东西
提前致谢。
发件人:http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#aop-proxying
Spring AOP uses either JDK dynamic proxies or CGLIB to create the
proxy for a given target object. (JDK dynamic proxies are preferred
whenever you have a choice).
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.
所以基本上,如果您的 class 有一个接口,spring 将通过该接口代理它,因此要正确执行建议,您必须通过接口引用该 bean。如果没有接口,它将为实际的 class 创建一个 CGLIB 代理,您可以通过 class 引用该 bean。
您可以通过设置覆盖此默认行为并强制使用 CGLIB 代理,从而强制使用基于 class 的建议:@EnableAspectJAutoProxy(proxyTargetClass=true)
其中的 javadoc 指出:"Indicate whether subclass-based (CGLIB) proxies are to be created as opposed to standard Java interface-based proxies."
正在学习 Spring、运行 一些我无法理解或找不到参考的东西。做了一个简约的项目来过滤掉混乱并使事情更清晰:1 个包 6 个文件,不包括 pom.xml :
1 App.java - 里面是 main() 方法。
package beantest;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.ApplicationContext;
public class App{
public static void main(String[] args){
ApplicationContext context = new AnnotationConfigApplicationContext(JavaConfig.class);
ClassAAA aaa = (ClassAAA) context.getBean(ClassAAA.class);
ClassBBB bbb = (ClassBBB) context.getBean(ClassBBB.class);
aaa.doSomething();
bbb.doSomething();
}
}
2 ClassAAA.java
package beantest;
public class ClassAAA{
public void doSomething(){
System.out.println("running 'doSomething()' by AAA object");
}
}
3 ClassBBB.java - ClassAAA 和 ClassBBB 之间的唯一区别是 BBB 实现了 InterfaceX。
package beantest;
public class ClassBBB implements InterfaceX{
public void doSomething(){
System.out.println("running 'doSomething()' by BBB object");
}
}
4 InterfaceX.java - 没有方法,在这种状态下。
package beantest;
public interface InterfaceX{
//void doSomething();
}
5 JavaConfig.java
package beantest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@EnableAspectJAutoProxy
public class JavaConfig{
@Bean
public ClassAAA aaa(){
return new ClassAAA();
}
@Bean
public ClassBBB bbb(){
return new ClassBBB();
}
@Bean
public Aspect1 aspect1(){
return new Aspect1();
}
}
6 Aspect1.java
package beantest;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class Aspect1{
@Before ("execution(* beantest.ClassAAA.doSomething(..))")
public void beforeAAAdoesSomething(){
System.out.println("##### BEFORE advice on AAA's doSomething() #####");
}
@Before ("execution(* beantest.ClassBBB.doSomething(..))")
public void beforeBBBdoesSomething(){
System.out.println("##### BEFORE advice on BBB's doSomething() #####");
}
}
*** 运行 这给出了预期的输出:
##### BEFORE advice on AAA's doSomething() #####
running 'doSomething()' by AAA object
##### BEFORE advice on BBB's doSomething() #####
running 'doSomething()' by BBB object
*** 取消注释 InterfaceX.java 和 运行 中的“doSomething”方法给出以下输出:
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'beantest.ClassBBB' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:353)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:340)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1093)
at beantest.App.main(App.java:12)
为什么 运行 作为接口实现的方法会阻止 Spring 在从未在任何地方提及所述接口的情况下找到 bean?
如果从这里我要注释掉 Aspect1.java 中关于 ClassBBB
的建议//@Before ("execution(* beantest.ClassBBB.doSomething(..))")
没有抛出异常,输出符合预期:
##### BEFORE advice on AAA's doSomething() #####
running 'doSomething()' by AAA object
running 'doSomething()' by BBB object
最后,改变
ClassBBB bbb = (ClassBBB) context.getBean(ClassBBB.class);
至
InterfaceX bbb = (InterfaceX) context.getBean(InterfaceX.class);
解决了未注释的建议和接口方法的问题。
我什么时候应该通过 class 查找实现接口的 bean?实验的时候无意中发现了这个东西
提前致谢。
发件人:http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#aop-proxying
Spring AOP uses either JDK dynamic proxies or CGLIB to create the proxy for a given target object. (JDK dynamic proxies are preferred whenever you have a choice).
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.
所以基本上,如果您的 class 有一个接口,spring 将通过该接口代理它,因此要正确执行建议,您必须通过接口引用该 bean。如果没有接口,它将为实际的 class 创建一个 CGLIB 代理,您可以通过 class 引用该 bean。
您可以通过设置覆盖此默认行为并强制使用 CGLIB 代理,从而强制使用基于 class 的建议:@EnableAspectJAutoProxy(proxyTargetClass=true)
其中的 javadoc 指出:"Indicate whether subclass-based (CGLIB) proxies are to be created as opposed to standard Java interface-based proxies."