当前位置: 首页 > news >正文

安徽池州网站制作seo从入门到精通

安徽池州网站制作,seo从入门到精通,wordpress上传图片裂了,网站开发容易做吗SpringBoot扩展篇:Scope和Lazy源码解析 1. 研究主题及Demo2. 注册BeanDefinition3. 初始化属性3.1 解决依赖注入3.2 创建代理 ContextAnnotationAutowireCandidateResolver#getLazyResolutionProxyIfNecessary3.3 代理拦截处理3.4 单例bean与原型bean创建的区别 4. …

SpringBoot扩展篇:@Scope和@Lazy源码解析

    • 1. 研究主题及Demo
    • 2. 注册BeanDefinition
    • 3. 初始化属性
      • 3.1 解决依赖注入
      • 3.2 创建代理 ContextAnnotationAutowireCandidateResolver#getLazyResolutionProxyIfNecessary
      • 3.3 代理拦截处理
      • 3.4 单例bean与原型bean创建的区别
    • 4. 总结

1. 研究主题及Demo

A class

@Component
public class A {@Lazy@Autowiredpublic B b;public B getB() {return b;}
}

B class

@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Component
public class B {
}

测试类

@SpringBootApplication
public class WebApplication{public static void main(String[] args) {ConfigurableApplicationContext run = SpringApplication.run(WebApplication.class, args);A a = run.getBean(A.class);System.out.println(a.b);System.out.println(a.b);System.out.println(a.b);}
}

研究问题1:为什么打印三次b对象的地址值不一样,从源码角度分析Spring是如何实现的?

在这里插入图片描述

研究问题2:为什么会debug看到的是代理对象,而打印出来的不是代理对象?

2. 注册BeanDefinition

在Spring对@Component扫描的时候,会调用ClassPathBeanDefinitionScanner#doScan生成beandefinition对象,可参考:
SpringBoot 源码解析5:ConfigurationClassPostProcessor整体流程和@ComponentScan源码分析

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;}

此时,Spring会通过AnnotationScopeMetadataResolver#resolveScopeMetadata扫描class上的@Scope注解,并通过candidate.setScope(scopeMetadata.getScopeName())将scope保存到beanDefinition中。

@Override
public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {ScopeMetadata metadata = new ScopeMetadata();if (definition instanceof AnnotatedBeanDefinition) {AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(annDef.getMetadata(), this.scopeAnnotationType);if (attributes != null) {metadata.setScopeName(attributes.getString("value"));ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");if (proxyMode == ScopedProxyMode.DEFAULT) {proxyMode = this.defaultProxyMode;}metadata.setScopedProxyMode(proxyMode);}}return metadata;
}

所以此时的B中的scope为prototype。
在这里插入图片描述
Spring默认为单例,所以此时A中的scope为singleton。

3. 初始化属性

3.1 解决依赖注入

想要更加完善的了解Spring属性值注入,可查看 SpringBoot扩展篇:Spring注入 @Autowired & @Resource

此时,A对象已经创建完毕,当对A对象的B字段赋值时,会调用 DefaultListableBeanFactory#resolveDependency 实现依赖注入。

@Override
@Nullable
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());if (Optional.class == descriptor.getDependencyType()) {return createOptionalDependency(descriptor, requestingBeanName);}else if (ObjectFactory.class == descriptor.getDependencyType() ||ObjectProvider.class == descriptor.getDependencyType()) {return new DependencyObjectProvider(descriptor, requestingBeanName);}else if (javaxInjectProviderClass == descriptor.getDependencyType()) {return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);}else {Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(descriptor, requestingBeanName);if (result == null) {result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);}return result;}
}

当getLazyResolutionProxyIfNecessary方法返回有值时,就会返回当前值,而当前值就是解析@Lazy注解,并对返回值进行了代理。

3.2 创建代理 ContextAnnotationAutowireCandidateResolver#getLazyResolutionProxyIfNecessary

@Override
@Nullable
public Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor, @Nullable String beanName) {return (isLazy(descriptor) ? buildLazyResolutionProxy(descriptor, beanName) : null);
}protected boolean isLazy(DependencyDescriptor descriptor) {for (Annotation ann : descriptor.getAnnotations()) {Lazy lazy = AnnotationUtils.getAnnotation(ann, Lazy.class);if (lazy != null && lazy.value()) {return true;}}MethodParameter methodParam = descriptor.getMethodParameter();if (methodParam != null) {Method method = methodParam.getMethod();if (method == null || void.class == method.getReturnType()) {Lazy lazy = AnnotationUtils.getAnnotation(methodParam.getAnnotatedElement(), Lazy.class);if (lazy != null && lazy.value()) {return true;}}}return false;
}protected Object buildLazyResolutionProxy(final DependencyDescriptor descriptor, final @Nullable String beanName) {Assert.state(getBeanFactory() instanceof DefaultListableBeanFactory,"BeanFactory needs to be a DefaultListableBeanFactory");final DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) getBeanFactory();TargetSource ts = new TargetSource() {@Overridepublic Class<?> getTargetClass() {return descriptor.getDependencyType();}@Overridepublic boolean isStatic() {return false;}@Overridepublic Object getTarget() {Object target = beanFactory.doResolveDependency(descriptor, beanName, null, null);if (target == null) {Class<?> type = getTargetClass();if (Map.class == type) {return Collections.emptyMap();}else if (List.class == type) {return Collections.emptyList();}else if (Set.class == type || Collection.class == type) {return Collections.emptySet();}throw new NoSuchBeanDefinitionException(descriptor.getResolvableType(),"Optional dependency not present for lazy injection point");}return target;}@Overridepublic void releaseTarget(Object target) {}};ProxyFactory pf = new ProxyFactory();pf.setTargetSource(ts);Class<?> dependencyType = descriptor.getDependencyType();if (dependencyType.isInterface()) {pf.addInterface(dependencyType);}return pf.getProxy(beanFactory.getBeanClassLoader());
}

isLazy方法:判断是否需要懒加载。显然,此时A对象的B字段上面有@Lazy注解,返回的是true。
buildLazyResolutionProxy方法:创建ProxyFactory代理对象,并返回该代理对象。当该代理对象调用方法时,会回调getTarget() 方法,从而从beanFactory中获取B对象。但是此时,B对象是prototype类型,不会保存到单例池singletonObjects中,所以每次获取B对象的时候,都是创建,每次都是不同的对象。

3.3 代理拦截处理

private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {private final AdvisedSupport advised;public DynamicAdvisedInterceptor(AdvisedSupport advised) {this.advised = advised;
}@Override
@Nullable
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {Object oldProxy = null;boolean setProxyContext = false;Object target = null;TargetSource targetSource = this.advised.getTargetSource();try {if (this.advised.exposeProxy) {// Make invocation available if necessary.oldProxy = AopContext.setCurrentProxy(proxy);setProxyContext = true;}// Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...target = targetSource.getTarget();Class<?> targetClass = (target != null ? target.getClass() : null);List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);Object retVal;// Check whether we only have one InvokerInterceptor: that is,// no real advice, but just reflective invocation of the target.if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {// We can skip creating a MethodInvocation: just invoke the target directly.// Note that the final invoker must be an InvokerInterceptor, so we know// it does nothing but a reflective operation on the target, and no hot// swapping or fancy proxying.Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);retVal = methodProxy.invoke(target, argsToUse);}else {// We need to create a method invocation...retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();}retVal = processReturnType(proxy, target, method, retVal);return retVal;}finally {if (target != null && !targetSource.isStatic()) {targetSource.releaseTarget(target);}if (setProxyContext) {// Restore old proxy.AopContext.setCurrentProxy(oldProxy);}}
}

在代理拦截器中, 回调了target方法。

3.4 单例bean与原型bean创建的区别

AbstractBeanFactory#doGetBean

在这里插入图片描述
可以看到,单例bean创建调用了getSingleton方法,再从中回调createBean创建bean的,而原型模式是直接调用createBean创建bean的。

DefaultSingletonBeanRegistry#getSingleton

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {Assert.notNull(beanName, "Bean name must not be null");synchronized (this.singletonObjects) {Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null) {if (this.singletonsCurrentlyInDestruction) {throw new BeanCreationNotAllowedException(beanName,"Singleton bean creation not allowed while singletons of this factory are in destruction " +"(Do not request a bean from a BeanFactory in a destroy method implementation!)");}if (logger.isDebugEnabled()) {logger.debug("Creating shared instance of singleton bean '" + beanName + "'");}beforeSingletonCreation(beanName);boolean newSingleton = false;boolean recordSuppressedExceptions = (this.suppressedExceptions == null);if (recordSuppressedExceptions) {this.suppressedExceptions = new LinkedHashSet<>();}try {singletonObject = singletonFactory.getObject();newSingleton = true;}catch (IllegalStateException ex) {// Has the singleton object implicitly appeared in the meantime ->// if yes, proceed with it since the exception indicates that state.singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null) {throw ex;}}catch (BeanCreationException ex) {if (recordSuppressedExceptions) {for (Exception suppressedException : this.suppressedExceptions) {ex.addRelatedCause(suppressedException);}}throw ex;}finally {if (recordSuppressedExceptions) {this.suppressedExceptions = null;}afterSingletonCreation(beanName);}if (newSingleton) {addSingleton(beanName, singletonObject);}}return singletonObject;}}

在单例bean创建的最后,会调用addSingleton方法将创建好的bean放入到singletonObjects中,而原型模式创建的bean不会!

4. 总结

研究问题1:为什么打印三次b对象的地址值不一样,从源码角度分析Spring是如何实现的?
研究问题2:为什么会debug看到的是代理对象,而打印出来的不是代理对象?

  1. Spring对A对象的B字段赋值的时候,实际上是返回的是一个代理对象。
  2. 而在打印一个对象的时候,会打印这个对象的toString方法。
  3. 此时会进入拦截器。而拦截器中,会回调代理对象的getTarget方法。
  4. getTarget方法中会通过beanFactory获取B,但是B是prototype,不会将创建好的bean保存到singletonObjects中,所以每次都会创建一个新的bean。
http://www.cotm.com.cn/news/564.html

相关文章:

  • 青岛开发区网站建设多少钱今天最新的新闻
  • 连云港建设公司网站seo排名优化软件
  • 建站公司网站模版注册域名要钱吗
  • 贵阳网站建设制作公司百度一下一下你就知道
  • 上海网站备案流程发布信息的免费平台
  • 有网站源码去哪里做营销策划案ppt优秀案例
  • 程序员做图网站外贸网站制作公司
  • wordpress批量发布文章太原百度推广排名优化
  • 江宁网站建设价格巨量广告投放平台
  • 女生学什么专业好深圳优化排名公司
  • 做网站好还是阿里巴巴好徐州seo管理
  • 河南智慧团建网站登录浏览广告赚钱的平台
  • 番禺区pc端网站建设代发推广百度首页包收录
  • 专业定制网站需要什么技能产品软文范例软文
  • 营销型网站sem投放策略广州头条新闻最新
  • 做网站一台电脑可以吗安卓优化大师官方版本下载
  • flash网站制作教程 下载百度推广公司哪家比较靠谱
  • 个人可以做建站网站么上海高玩seo
  • 网站建设与优化在线葡京在线葡京
  • 下拉框代码自做生成网站网站排名top排行榜
  • 网站建设 推广优化电池充电什么意思
  • 品牌高端网站制作南宁百度快速优化
  • 深圳企业网站建设优惠百度seo优化网站
  • 西安模板网站长春网站建设公司哪家好
  • wordpress如何生成网站地图免费优化网站
  • 如何用wd做网站设计开发一个平台需要多少钱
  • 租车网站建设打开网站搜索
  • 零基础学做网站要多久鄂尔多斯seo
  • asp网站建设运用的技术网站seo排名优化方法
  • 静态网站模板 大气自己如何制作一个小程序