@Scope注解详解

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

提示:这里可以添加本文要记录的大概内容:

这里记录下@Scope注解的一些知识点


提示:以下是本篇文章正文内容,下面案例可供参考

一、@Scope是什么,有什么用?

@Scope注解主要作用是调节Ioc容器中的作用域,在Spring IoC容器中主要有以下五种作用域:基本作用域:singleton(单例)、prototype(多例);Web 作用域(reqeust、session、globalsession),自定义作用域。

二、@Scope注解源码解析

1.使用@Scope注解对象注入到IOC容器过程

(1) springboot 程序启动时会对classpath路径下的包中的类进行扫描,将类解析成BeanDefinition,在扫描完BeanDefinition后会对其进行注册,便于后面创建Bean时使用

    // org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan	
    /**
	 * Perform a scan within the specified base packages,
	 * returning the registered bean definitions.
	 * <p>This method does <i>not</i> register an annotation config processor
	 * but rather leaves this up to the caller.
	 * @param basePackages the packages to check for annotated classes
	 * @return set of beans registered if any for tooling registration purposes (never {@code null})
	 */
	protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
		Assert.notEmpty(basePackages, "At least one base package must be specified");
		Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
		for (String basePackage : basePackages) {
			Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
			for (BeanDefinition candidate : candidates) {
				ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
				candidate.setScope(scopeMetadata.getScopeName());
				String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
				if (candidate instanceof AbstractBeanDefinition) {
					postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
				}
				if (candidate instanceof AnnotatedBeanDefinition) {
					AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
				}
				if (checkCandidate(beanName, candidate)) {
					BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
					definitionHolder =
							AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
					beanDefinitions.add(definitionHolder);
					registerBeanDefinition(definitionHolder, this.registry);
				}
			}
		}
		return beanDefinitions;
	}

(2)接着会对扫描出来的BeanDefinition处理,其中下面代码对扫描完的Bean的作用域的代理模式进行处理:


    // org.springframework.context.annotation.AnnotationConfigUtils#applyScopedProxyMode	
    static BeanDefinitionHolder applyScopedProxyMode(
            ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {

        ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
        if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
            return definition;
        }
        boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
        return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
    }

上面代码会判断作用域的代码模式,如果是ScopedProxyMode.NO,不进行代理处理直接返回BeanDefinition,如果不是NO,再判断是否是ScopedProxyMode.TARGET_CLASS,在后续逻辑中会根据此来决定是否创建目标类的代理类。

// org.springframework.aop.scope.ScopedProxyUtils#createScopedProxy	
public static BeanDefinitionHolder createScopedProxy(BeanDefinitionHolder definition,
			BeanDefinitionRegistry registry, boolean proxyTargetClass) {

		String originalBeanName = definition.getBeanName();
		BeanDefinition targetDefinition = definition.getBeanDefinition();
		String targetBeanName = getTargetBeanName(originalBeanName);

		// Create a scoped proxy definition for the original bean name,
		// "hiding" the target bean in an internal target definition.
		RootBeanDefinition proxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class);
		proxyDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, targetBeanName));
		proxyDefinition.setOriginatingBeanDefinition(targetDefinition);
		proxyDefinition.setSource(definition.getSource());
		proxyDefinition.setRole(targetDefinition.getRole());

		proxyDefinition.getPropertyValues().add("targetBeanName", targetBeanName);
		if (proxyTargetClass) {
			targetDefinition.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
			// ScopedProxyFactoryBean's "proxyTargetClass" default is TRUE, so we don't need to set it explicitly here.
		}
		else {
			proxyDefinition.getPropertyValues().add("proxyTargetClass", Boolean.FALSE);
		}

		// Copy autowire settings from original bean definition.
		proxyDefinition.setAutowireCandidate(targetDefinition.isAutowireCandidate());
		proxyDefinition.setPrimary(targetDefinition.isPrimary());
		if (targetDefinition instanceof AbstractBeanDefinition) {
			proxyDefinition.copyQualifiersFrom((AbstractBeanDefinition) targetDefinition);
		}

		// The target bean should be ignored in favor of the scoped proxy.
		targetDefinition.setAutowireCandidate(false);
		targetDefinition.setPrimary(false);

		// Register the target bean as separate bean in the factory.
		registry.registerBeanDefinition(targetBeanName, targetDefinition);

		// Return the scoped proxy definition as primary bean definition
		// (potentially an inner bean).
		return new BeanDefinitionHolder(proxyDefinition, originalBeanName, definition.getAliases());
	}

上面过程向BeanDefinitionRegistry中注入了两个BeanDefinition分别是目标类、目标类的代理类(

beanClass为ScopedProxyFactoryBean.class)。

最终返回BeanDefinitionHolder的beanName为目标类名,beanClass为ScopedProxyFactoryBean.class的BeanDenifition。

return new BeanDefinitionHolder(proxyDefinition, originalBeanName, definition.getAliases());

其中ScopedProxyFactoryBean类实现了BeanFactoryAware,Aware接口由Spring在AbstractAutowireCapableBeanFactory.initializeBean(beanName, bean,mbd)方法中通过调用invokeAwareMethods(beanName, bean)方法和applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName)触发Aware方法的调用setBeanFactory方法,该方法中会创建一个目前类的代理类暂存在其proxy变量中。

// org.springframework.aop.scope.ScopedProxyFactoryBean#setBeanFactory
@Override
public void setBeanFactory(BeanFactory beanFactory) {
   if (!(beanFactory instanceof ConfigurableBeanFactory)) {
      throw new IllegalStateException("Not running in a ConfigurableBeanFactory: " + beanFactory);
   }
   ConfigurableBeanFactory cbf = (ConfigurableBeanFactory) beanFactory;

   this.scopedTargetSource.setBeanFactory(beanFactory);

   ProxyFactory pf = new ProxyFactory();
   pf.copyFrom(this);
   pf.setTargetSource(this.scopedTargetSource);

   Assert.notNull(this.targetBeanName, "Property 'targetBeanName' is required");
   Class<?> beanType = beanFactory.getType(this.targetBeanName);
   if (beanType == null) {
      throw new IllegalStateException("Cannot create scoped proxy for bean '" + this.targetBeanName +
            "': Target type could not be determined at the time of proxy creation.");
   }
   if (!isProxyTargetClass() || beanType.isInterface() || Modifier.isPrivate(beanType.getModifiers())) {
      pf.setInterfaces(ClassUtils.getAllInterfacesForClass(beanType, cbf.getBeanClassLoader()));
   }

   // Add an introduction that implements only the methods on ScopedObject.
   ScopedObject scopedObject = new DefaultScopedObject(cbf, this.scopedTargetSource.getTargetBeanName());
   pf.addAdvice(new DelegatingIntroductionInterceptor(scopedObject));

   // Add the AopInfrastructureBean marker to indicate that the scoped proxy
   // itself is not subject to auto-proxying! Only its target bean is.
   pf.addInterface(AopInfrastructureBean.class);

   this.proxy = pf.getProxy(cbf.getBeanClassLoader());
}

在注入目标对象时,将会时用beanName从BeanDefinitionRegistry中取出beanclass为ScopedProxyFactoryBean.class的BeanDenifition,使用该BeanDenifition创建一个实例,创建完实例后会调用getObjectForBeanInstance方法来获取beanInstance,如果时FactoryBean则会调用其getObject()方法。

// org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean				
// Create bean instance.
				if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, () -> {
						try {
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							// Explicitly remove instance from singleton cache: It might have been put there
							// eagerly by the creation process, to allow for circular reference resolution.
							// Also remove any beans that received a temporary reference to the bean.
							destroySingleton(beanName);
							throw ex;
						}
					});
					beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}

// org.springframework.beans.factory.support.AbstractBeanFactory#getObjectForBeanInstance	
	protected Object getObjectForBeanInstance(
			Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

		// Don't let calling code try to dereference the factory if the bean isn't a factory.
		if (BeanFactoryUtils.isFactoryDereference(name)) {
			if (beanInstance instanceof NullBean) {
				return beanInstance;
			}
			if (!(beanInstance instanceof FactoryBean)) {
				throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
			}
			if (mbd != null) {
				mbd.isFactoryBean = true;
			}
			return beanInstance;
		}

		// Now we have the bean instance, which may be a normal bean or a FactoryBean.
		// If it's a FactoryBean, we use it to create a bean instance, unless the
		// caller actually wants a reference to the factory.
		if (!(beanInstance instanceof FactoryBean)) {
			return beanInstance;
		}

		Object object = null;
		if (mbd != null) {
			mbd.isFactoryBean = true;
		}
		else {
			object = getCachedObjectForFactoryBean(beanName);
		}
		if (object == null) {
			// Return bean instance from factory.
			FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
			// Caches object obtained from FactoryBean if it is a singleton.
			if (mbd == null && containsBeanDefinition(beanName)) {
				mbd = getMergedLocalBeanDefinition(beanName);
			}
			boolean synthetic = (mbd != null && mbd.isSynthetic());
			object = getObjectFromFactoryBean(factory, beanName, !synthetic);
		}
		return object;
	}

 目标类会被解析成ScopedProxyFactoryBean,而ScopedProxyFactoryBean是FactoryBean,所以会调用ScopedProxyFactoryBean的getObject方法,而ScopedProxyFactoryBean的getObject方法返回的是其属性proxy即创建的目标类的代理类,

	@Override
	public Object getObject() {
		if (this.proxy == null) {
			throw new FactoryBeanNotInitializedException();
		}
		return this.proxy;
	}

2.@Scope注解标注的对象的获取过程

后续更新中......


总结

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring是一个Java开发框架,提供了许多注解来简化开发。下面是Spring中常用的注解详解: 1. @Autowired:自动装配,用于自动注入依赖项。 2. @Component:用于标记一个类为Spring容器管理的组件。 3. @Controller:用于标记一个类为Spring MVC控制器。 4. @Service:用于标记一个类为服务层组件。 5. @Repository:用于标记一个类为数据访问层组件。 6. @RequestMapping:用于映射请求到处理程序方法。 7. @PathVariable:用于获取请求URL中的变量值。 8. @RequestParam:用于获取请求参数的值。 9. @ResponseBody:用于将返回值直接写入响应体中。 10. @RestController:用于标记一个类为Spring MVC控制器,并且默认所有方法都返回JSON格式的数据。 11. @Configuration:用于标记一个类为配置类,相当于一个XML配置文件。 12. @Bean:用于在配置类中声明一个Bean。 13. @Value:用于获取配置文件中的属性值。 14. @Qualifier:用于指定自动装配时使用的Bean名称。 15. @Scope:用于指定Bean的作用域,例如singleton、prototype等。 16. @Transactional:用于标记一个方法为事务方法。 17. @Async:用于标记一个方法为异步方法。 18. @PostConstruct:用于标记一个方法为Bean初始化方法。 19. @PreDestroy:用于标记一个方法为Bean销毁方法。 以上是Spring中常见的注解详解,使用这些注解可以使开发更加简单和高效。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值