Spring中的作用域代理是什么?

Spring中的作用域代理是什么?,第1张

Spring中的作用域代理是什么?

@Transactional
行为生成的代理的作用与作用域代理不同。

@Transactional
代理是包装特定bean来添加会话管理行为的代理。所有方法调用将在委派给实际bean之前和之后执行事务管理。

如果您进行说明,它看起来像

main -> getCounter -> (cglib-proxy -> MyBeanB)

就我们的目的而言,您基本上可以忽略其行为(删除

@Transactional
该行为,除了没有cglib代理外,您应该会看到相同的行为)。

@Scope
代理行为有所不同。该文档指出:

[…]您需要注入一个代理对象,该对象公开与范围对象相同的公共接口, 但也可以从相关范围 (例如HTTP请求)中 检索实际目标对象
,并将方法调用委托给实际对象。

Spring真正在做的是为代表代理的工厂类型创建一个singleton bean定义。但是,相应的代理对象会在每次调用时在上下文中查询实际的bean。

如果您进行说明,它看起来像

main -> getCounter -> (cglib-scoped-proxy -> context/bean-factory -> new MyBeanB)

由于

MyBeanB
是原型Bean,因此上下文将始终返回新实例。

就此答案而言,假设您

MyBeanB
直接使用

MyBeanB beanB = context.getBean(MyBeanB.class);

实际上,这是Spring为满足

@Autowired
注射目标所做的工作。


在第一个示例中

@Service@Scope(value = "prototype")public class MyBeanB {

您声明原型Bean定义(通过注释)。

@Scope
有一个
proxyMode
元素

指定是否应将组件配置为作用域代理,如果是,则指定代理是基于接口还是基于子类。

默认值为

ScopedProxyMode.DEFAULT
,这通常表示除非在组件扫描指令级别配置了其他默认值,否则
不应创建任何作用域代理

因此,Spring不会为生成的bean创建作用域代理。您使用

MyBeanB beanB = context.getBean(MyBeanB.class);

现在,您具有对

MyBeanB
由Spring创建的新对象的引用。就像任何其他Java对象一样,方法调用将直接转到引用的实例。

如果

getBean(MyBeanB.class)
再次使用,Spring将返回一个新实例,因为bean定义是针对原型bean的。您没有这样做,因此所有方法调用都转到同一个对象。


在第二个示例中

@Service@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)public class MyBeanB {

您声明通过cglib实现的作用域代理。当从Spring请求这种类型的bean时

MyBeanB beanB = context.getBean(MyBeanB.class);

Spring知道这

MyBeanB
是一个作用域代理,因此返回一个满足API
MyBeanB
(即实现其所有公共方法)的代理对象,该API
内部知道如何
MyBeanB
为每个方法调用检索类型的实际bean 。

尝试跑步

System.out.println("singleton?: " + (context.getBean(MyBeanB.class) == context.getBean(MyBeanB.class)));

这将返回

true
暗示Spring正在返回单例代理对象(而不是原型Bean)的事实。

在代理实现内部的方法调用上,Spring将使用一个特殊的

getBean
版本,该版本知道如何区分代理定义和实际的
MyBeanB
bean定义。这将返回一个新
MyBeanB
实例(因为它是原型),Spring会通过反射(经典
Method.invoke
)将方法调用委托给它。


您的第三个示例与您的第二个示例基本相同。



欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5500719.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-12
下一篇 2022-12-12

发表评论

登录后才能评论

评论列表(0条)

保存