织梦修改网站标题,万网域名注册查询,众创空间网站建设方案,论基层门户网站的建设SpringBoot扩展篇#xff1a;Scope和Lazy源码解析 1. 研究主题及Demo2. 注册BeanDefinition3. 初始化属性3.1 解决依赖注入3.2 创建代理 ContextAnnotationAutowireCandidateResolver#getLazyResolutionProxyIfNecessary3.3 代理拦截处理3.4 单例bean与原型bean创建的区别 4. … SpringBoot扩展篇Scope和Lazy源码解析 1. 研究主题及Demo2. 注册BeanDefinition3. 初始化属性3.1 解决依赖注入3.2 创建代理 ContextAnnotationAutowireCandidateResolver#getLazyResolutionProxyIfNecessary3.3 代理拦截处理3.4 单例bean与原型bean创建的区别 4. 总结 1. 研究主题及Demo
A class
Component
public class A {LazyAutowiredpublic 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 源码解析5ConfigurationClassPostProcessor整体流程和ComponentScan源码分析
protected SetBeanDefinitionHolder doScan(String... basePackages) {Assert.notEmpty(basePackages, At least one base package must be specified);SetBeanDefinitionHolder beanDefinitions new LinkedHashSet();for (String basePackage : basePackages) {SetBeanDefinition 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 SetString 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);ListObject 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看到的是代理对象而打印出来的不是代理对象 Spring对A对象的B字段赋值的时候实际上是返回的是一个代理对象。而在打印一个对象的时候会打印这个对象的toString方法。此时会进入拦截器。而拦截器中会回调代理对象的getTarget方法。getTarget方法中会通过beanFactory获取B但是B是prototype不会将创建好的bean保存到singletonObjects中所以每次都会创建一个新的bean。