Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/362.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么不';当我按类(而不是接口)查找JDK动态代理包装的bean时,我是否遇到任何异常? 让我们考虑下面的Bean: @Service @Scope(value = "prototype", proxyMode = ScopedProxyMode.INTERFACES) public class MyBeanB implements MyBeanBInterface { private static final AtomicLong COUNTER = new AtomicLong(0); private Long index; public MyBeanB() { index = COUNTER.getAndIncrement(); System.out.println("constructor invocation:" + index); } @Transactional @Override public long getCounter() { return index; } } 并考虑2种不同用法: 用法1:_Java_Spring_Spring Boot_Spring Aop_Dynamic Proxy - Fatal编程技术网

Java 为什么不';当我按类(而不是接口)查找JDK动态代理包装的bean时,我是否遇到任何异常? 让我们考虑下面的Bean: @Service @Scope(value = "prototype", proxyMode = ScopedProxyMode.INTERFACES) public class MyBeanB implements MyBeanBInterface { private static final AtomicLong COUNTER = new AtomicLong(0); private Long index; public MyBeanB() { index = COUNTER.getAndIncrement(); System.out.println("constructor invocation:" + index); } @Transactional @Override public long getCounter() { return index; } } 并考虑2种不同用法: 用法1:

Java 为什么不';当我按类(而不是接口)查找JDK动态代理包装的bean时,我是否遇到任何异常? 让我们考虑下面的Bean: @Service @Scope(value = "prototype", proxyMode = ScopedProxyMode.INTERFACES) public class MyBeanB implements MyBeanBInterface { private static final AtomicLong COUNTER = new AtomicLong(0); private Long index; public MyBeanB() { index = COUNTER.getAndIncrement(); System.out.println("constructor invocation:" + index); } @Transactional @Override public long getCounter() { return index; } } 并考虑2种不同用法: 用法1:,java,spring,spring-boot,spring-aop,dynamic-proxy,Java,Spring,Spring Boot,Spring Aop,Dynamic Proxy,在这种情况下,应用程序无法启动并打印: *************************** APPLICATION FAILED TO START *************************** Description: The bean 'myBeanB' could not be injected as a 'my.pack.MyBeanB' because it is a JDK dynamic proxy that implements: my.pack.MyBe

在这种情况下,应用程序无法启动并打印:

***************************
APPLICATION FAILED TO START
***************************

Description:

The bean 'myBeanB' could not be injected as a 'my.pack.MyBeanB' because it is a JDK dynamic proxy that implements:
    my.pack.MyBeanBInterface


Action:

Consider injecting the bean as one of its interfaces or forcing the use of CGLib-based proxies by setting proxyTargetClass=true on @EnableAsync and/or @EnableCaching.
我希望看到它,因为我要求spring为bean
MyBeanB
创建JDK动态代理,而该代理不是MyBeanB的子类型。我们可以这样轻松地修复它:

@Service
public class MyBeanA {
    @Autowired
    private MyBeanBInterface myBeanB;   
    ....
}
用法2: 令人惊讶的是,它在没有任何运行时异常的情况下工作,但我希望在这种情况下看到
NoSuchBeanDefinitionException
,因为int case1应用程序无法启动

感谢评论中的家伙-我检查了
beanB
的类,它是
my.pack.MyBeanB$$EnhancerBySpringCGLIB$$b1346261
,因此Spring使用CGLIB创建代理,但它与bean定义(
@Scope(value=“prototype”,proxyMode=ScopedProxyMode.INTERFACES
)相矛盾,看起来像个bug。 )


你能解释为什么它适用于案例2而不适用于案例1吗?

正如我在对Spring的评论中向你解释的那样,AOP可以根据情况同时使用CGLIB和JDK代理。默认情况下是用于实现接口的类的JDK代理,但是您也可以为它们强制使用CGLIB。对于未实现接口的类,只保留CGLIB,因为JDK代理只能基于接口创建动态代理

因此,在案例1中,您明确表示需要接口代理,即JDK代理:

@Scope(value=“prototype”,proxyMode=ScopedProxyMode.INTERFACES)
但是
MyBeanA
没有实现任何接口。因此,您会得到在本例中看到的错误消息

然而,在案例2中,您使用
ApplicationContext.getBean(..)
来创建代理。在这里,您依靠Spring来决定选择哪种代理类型,而不是试图强制执行任何操作。因此,通过CGLIB代理成功

这一点也不奇怪

如果要避免案例1中的错误消息,可能应该使用
ScopedProxyMode.TARGET\u CLASS


更新:对不起,我被你类似的、不起眼的类名
MyBeanA
MyBeanB
激怒了。下次使用更具描述性、更简洁的类名称是有意义的,最理想的是那些描述场景中类的角色的类名称,如
MyService
MyInterface
MyScopedBean

无论如何,我再次阅读了你的问题和错误消息。错误消息表示,根据您的注释,正在生成一个基于接口的代理,但您正试图将其注入到类类型中。您可以通过如下方式声明它来修复此问题:

@Service
public class MyBeanA {
    @Autowired
    private MyBeanBInterface myBeanB;   
    ....
}
@Autowired
私有myBeanB接口myBeanB;
在case/usage 2中,您再次显式声明了一个类,而不是bean的接口类型。正如我所说,Spring试图通过唯一可能的方式满足您的需求,即为类创建CGLIB代理。您可以通过声明接口类型来修复此问题,并将获得预期的JDK代理:

MyBeanInterface MyBeanInterface=appContext.getBean(MyBeanInterface.class);
System.out.println(myBeanBInterface.getCounter());
System.out.println(myBeanBInterface.getClass());

更新2:根据您的评论,我认为您仍然不理解OOP的基本事实:如果您有

  • class
    Base
    和class
    Sub扩展Base
  • 接口
    Base
    和类
    子实现Base
您可以声明
Base b=new-Base()
,但当然不能声明
Sub s=new-Base()
,因为
Sub
也是
Base
,但不是每个
Base
都是
Sub
。例如,如果您还有
OtherSub扩展Base
,则在尝试将
Base
对象分配给
Sub
变量时,它可能是
OtherSub
实例。这就是为什么dot甚至不使用
Sub s=(Sub)myBaseObject
进行编译

到目前为止,一切顺利。现在再次查看您的代码:

用法1中,您拥有
@Autowired private MyBeanB MyBeanB
但配置了
MyBeanB
以生成JDK代理,即将创建一个新的代理类,其父类
proxy
直接实现
MyBeanB接口
。也就是说,您有两个不同的类,它们都直接实现相同的接口。由于我上面解释的原因,这些类彼此不兼容。关于接口,我们有类层次结构

mybeanb接口
MyBeanB
MyBeanB_JDKProxy
因此,您不能将
MyBeanB\u JDKProxy
注入
MyBeanB
字段,因为代理对象不是
MyBeanB
的实例。你不明白吗?问题就在电脑前面,没有神秘的Spring bug。您已将其配置为失败

这就是为什么我告诉您将代码更改为
@Autowired private myBeanB接口myBeanB因为它当然可以工作,因为代理实现了接口,而且一切都很好。我还告诉过你,或者你可以保留
@Autowired private MyBeanB MyBeanB如果使用范围声明的
proxyMode=ScopedProxyMode.TARGET\u CLASS

在用法2中,问题是相同的:你说的是
getBean(ClassB.class)
,也就是说,你明确指示Spring为该类创建一个代理。但是对于一个类,您不能创建JDK代理,只能创建CGLIB代理,这就是Spring所做的。同样,我通过指示您使用
getBean(MyBeanBInterface.class)
给出了解决方案。然后得到预期的JDK代理

春天足够聪明,两者兼而有之

  • 使JDK代理处于用法1中
    MyBeanB beanB = context.getBean(MyBeanB.class);
    System.out.println(beanB.getCounter());