写点什么

SpringBoot 之 ScopedProxyMode

用户头像
梦倚栏杆
关注
发布于: 2021 年 06 月 17 日

一、代理模式种类:

代理模式种类:

public enum ScopedProxyMode {
/** * Default typically equals {@link #NO}, unless a different default * has been configured at the component-scan instruction level. */ DEFAULT,
/** * Do not create a scoped proxy. * <p>This proxy-mode is not typically useful when used with a * non-singleton scoped instance, which should favor the use of the * {@link #INTERFACES} or {@link #TARGET_CLASS} proxy-modes instead if it * is to be used as a dependency. */ NO,
/** * Create a JDK dynamic proxy implementing <i>all</i> interfaces exposed by * the class of the target object. */ INTERFACES,
/** * Create a class-based proxy (uses CGLIB). */ TARGET_CLASS;
}
复制代码

二、代理模式的处理

public class AnnotationConfigUtils {  //应用代理模式  static BeanDefinitionHolder applyScopedProxyMode(ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {		ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();    //不用代理,直接返回		if (scopedProxyMode.equals(ScopedProxyMode.NO)) {			return definition;		}    //是否使用cglib代理    boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);		return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);	}}
class ScopedProxyCreator { ScopedProxyCreator() { }
public static BeanDefinitionHolder createScopedProxy(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry, boolean proxyTargetClass) { return ScopedProxyUtils.createScopedProxy(definitionHolder, registry, proxyTargetClass); }
public static String getTargetBeanName(String originalBeanName) { return ScopedProxyUtils.getTargetBeanName(originalBeanName); }}
public abstract class ScopedProxyUtils { public static BeanDefinitionHolder createScopedProxy(BeanDefinitionHolder definition, BeanDefinitionRegistry registry, boolean proxyTargetClass) { //将该definition重新定义一个代理的definition,并注入到该beanFactory }}
复制代码


创建代理的过程:

  1. RootBeanDefinition proxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class);

  2. proxyDefinition 开始赋值

  • 初始化: sourceDefinition=definition.getBeanDefinition(); sourceBeanName=definition.getBeanName(); proxyBeanName = getTargetBeanName(originalBeanName);

  • 设置装饰 bean: setDecoratedDefinition(new BeanDefinitionHolder(sourceDefinition, proxyBeanName));

  • 设置原始 bean: setOriginatingBeanDefinition(sourceDefinition);

  • 设置 source:setSource(definition.getSource());

  • 设置 role: setRole(sourceDefinition.getRole());

  • 添加属性值: targetBeanName=proxyBeanName; proxyTargetClass= isProxy;

  • 设置是否自动注入: setAutowireCandidate(sourceDefinition.isAutowireCandidate())

  • 设置是否主: setPrimary(sourceDefinition.isPrimary());

  • 如果是抽象 bean 对象,copy 需要自动注入的属性值 copyQualifiersFrom((AbstractBeanDefinition) sourceDefinition);

  1. 修改 sourceDefinition 部分属性值:

  • sourceDefinition.setAutowireCandidate(false);

  • sourceDefinition.setPrimary(false);

  • 将 definition 注入到当前的 beanFactory(proxyBeanName, sourceDefinition)

  1. 创建新的 BeanDefinitionHolder,并返回。

new BeanDefinitionHolder(proxyDefinition, sourceBeanName, definition.getAliases());


todo: 为啥要这么搞呢?目的是什么?

三、代理模式处理过程的调用场景:

场景一、通过 ScopedProxyUtils 调用(基本属于内部调用,忽略)

场景二、ScopedProxyBeanDefinitionDecorator 主要是被 AopNamespaceHandler 调用

日常 aop 使用场景

场景三、通过 ScopedProxyCreator 调用


场景四:通过 AnnotationConfigUtils 调用

主要是 component 等注解 bean


场景五:ConfigurationClassBeanDefinitionReader 调用:主要是加载 beanMethods 注解

class ConfigurationClassBeanDefinitionReader {  private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {      if (proxyMode != ScopedProxyMode.NO) {			  BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(					new BeanDefinitionHolder(beanDef, beanName), this.registry, proxyMode == ScopedProxyMode.TARGET_CLASS);			   beanDefToRegister = new ConfigurationClassBeanDefinition(					(RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata);		 }  }}
复制代码

转化为流程图:


最下面几个就是加载 bean 注解相关的类

四、代码样例直观感受

@Configuration@ConfigurationProperties(prefix = "person")public class Person {    private String name;
public String getName() { return name; }
public void setName(String name) { this.name = name; }}
@RestControllerpublic class PersonController { @Autowired private Person person;}
复制代码

调试看 PersonController 里 person 内容:

  1. ScopedProxyMode.DEFAULT(不添加注解,默认是该模式)

2.ScopedProxyMode.TARGET_CLASS

3.ScopedProxyMode.No(添加该 scope)


发布于: 2021 年 06 月 17 日阅读数: 14
用户头像

梦倚栏杆

关注

还未添加个人签名 2018.04.22 加入

还未添加个人简介

评论

发布
暂无评论
SpringBoot之ScopedProxyMode