精华内容
下载资源
问答
  • spring源码解读

    万次阅读 多人点赞 2019-04-29 11:46:20
    1、IOC(控制反转)、AOP(切面)、DI (依赖注入)是spring的核心部分 Spring是一种设计思想的体现,发生了“主从换位”的变化。应用程序由主动的创建对象,转换称了从IOC容器里获取对象,对象的创建、解析和注册...

    1、IOC(控制反转)、AOP(切面)、DI (依赖注入)是spring的核心部分

        Spring是一种设计思想的体现,发生了“主从换位”的变化。应用程序由主动的创建对象,转换称了从IOC容器里获取对象,对象的创建、解析和注册都由Spring来替用户实现,用户只管定义。

    2、IoC容器的设计与实现--Bean组件与Context组件

    使用Spring时,它首先替我们完成的时IOC容器的初始化,初始化的过程包括定义(BeanDefinition)、载入定义(loadBeanDefinitions,包含了解析的方法)、注册定义(registerBeanDefinitions),注册最后落实到代码中就是

    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(256);
    
    this.beanDefinitionMap.put(beanName, beanDefinition);

    注册到map集合中, 将BeanName作为键, BeanDefinition作为值保存。接下来看具体的源码,加深IOC容器初始化的过程理解

    2.1Bean组件

    bean组件在Spring的org.springframework.beans包下。IOC容器的初始化就在这个包里完成的,定义、载入、注册,对于使用者来说只要完成bean的定义就可以了,其他两个由 Spring 在内部帮我们完成了,对我们来说是透明的。

    bean的定义我们不多说,可以用配置文件定义bean,也可以用注解的方式,接下来我们看下Spring的做了那些操作:

    2.1.2 BeanFactory概述

    BeanFactory是Spring bean容器的根接口.提供获取bean,是否包含bean,是否单例与原型,获取bean类型,bean 别名的方法 。

    2.1.3BeanFactory的继承关系

    我们可以看到DefaultListableBeanFactory  是最终的实现类,它实现了所有的接口,它也是Spring框架里核心的类之一

    2.1.4BeanDefinition概述

    BeanDefinition是一个接口类,Bean 的定义主要由 BeanDefinition 实现,项目启动首先是读取bean的xml配置文件,然后解析xml文件中的各种bean的定义,将xml文件中的每一个<bean />元素分别转换解析成一个BeanDefinition对象,其中保存了从配置文件中读取到的该bean的各种信息,以后所有的操作都是对这个对象的操作。

    2.1.5 BeanDefinitionReader概述

    BeanDefinitionReader同样也是接口类,读取xml配置文件,解析为BeanDefinition对象过程是繁琐的,整个解析过程主要通过下图中的类完成:

    2.1.6BeanDefinitionHolder概述

    BeanDefinitionHolder是一个class实现类,BeanDefinitionHolder对象中持有的BeanDefinition实例的引用,还有beanName,还有bean的别名

    先对这几个类有个大体的了解,接下来从源码中看它们实际的作用。

    2.1.7Bean Definition从加载、解析、处理、注册到BeanFactory的过程,也就是IOC容器的初始化过程

    1. Bean Definition加载
      用配置文件的方式定义bean ,首先要做的就是读取xml文件
      public static  void main(String[] args){//直接使用BeanFactory 作为容器
            String xmlPath = "applicationContext.xml";
            BeanFactory factory = new XmlBeanFactory(new ClassPathResource(xmlPath));
            userService = (UserService) factory.getBean("userService");
            userService.add();
      }
      在XmlBeanDefinitionReader类中
      &1.loadBeanDefinitions方法从xml文件中加载beanDefinition,将Resource转化为EncodedResource对象,交给它的重载方法来做加载前的准备,实际去加载xml文件的是方法doLoadBeanDefinitions(InputSource inputSource, Resource resource),
      
      public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException{
      ....
        return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
      ....
      }
      &2.doLoadBeanDefinitions方法中加载得到一个Document对象,把Document和resource交给registerBeanDefinitions完成注册
      
      protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource){
      ....
        Document doc = doLoadDocument(inputSource, resource);
        return registerBeanDefinitions(doc, resource);
      ....
      }
      &3.registerBeanDefinitions(Document doc, Resource resource)方法,这里实际上是创建了一个BeanDefinitionDocumentReader对象然后让它来完成。
      
      public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
         BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
         int countBefore = getRegistry().getBeanDefinitionCount();
         documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
         return getRegistry().getBeanDefinitionCount() - countBefore;
      }
      
    2. Bean Definition解析

      在DefaultBeanDefinitionDocumentReader类中
      DefaultBeanDefinitionDocumentReader 是BeanDefinitionDocumentReader的实现类,这个类来实际的解析<bean/>标签
      &1.registerBeanDefinitions()也做的前期准备,真正去解析文件的方法是doRegisterBeanDefinitions()
         
      public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
                    ....
                   doRegisterBeanDefinitions(root);
      }

      &2.doRegisterBeanDefinitions方法将</beans>节点下的每一个<bean/>相对应的bean definition注册。但是真正做这件事的是另一个方法 parseBeanDefinitions(root, this.delegate);
      protected void doRegisterBeanDefinitions(Element root){
           ....
           parseBeanDefinitions(root, this.delegate);
           ....
      }
      &3.<beans/>中还包含<bean/>元素,需要对bean元素进行解析,parseBeanDefinitions方法中调用来
      parseDefaultElement方法来完成对<bean/>元素的解析,具体分解析过程有processBeanDefinition(ele, delegate)方法来实现,就是对beanDefinition的处理。
    3. Bean Definition处理
        在DefaultBeanDefinitionDocumentReader类中
      &1.
      processBeanDefinition方法中将Element对象转化成了BeanDefinitionHolder对象。这个BeanDefinitionHolder对象中持有的BeanDefinition实例的引用,还有beanName,还有bean的别名。
            然后将BeanDefinitionHolder对象和特定的bean工厂作为参数交给BeanDefinitionReaderUtils类来处理来进行注册。到了实际的注册步骤啦
      protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
         BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
         if (bdHolder != null) {
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
            try {
               // Register the final decorated instance.
               BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
            }
            catch (BeanDefinitionStoreException ex) {
               getReaderContext().error("Failed to register bean definition with name '" +
                     bdHolder.getBeanName() + "'", ele, ex);
            }
            // Send registration event.
            getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
         }
      }
    4. Bean Definition注册
      在BeanDefinitionReaderUtils类中

      public static void registerBeanDefinition(
            BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
            throws BeanDefinitionStoreException {

         // Register bean definition under primary name.
         String beanName = definitionHolder.getBeanName();
         registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

         // Register aliases for bean name, if any.
         String[] aliases = definitionHolder.getAliases();
         if (aliases != null) {
            for (String alias : aliases) {
               registry.registerAlias(beanName, alias);
            }
         }
      }

      DefaultListableBeanFactory类中,在这个方法中,将BeanDefinition 注册到了ConcurrentHashMap对象中了。注册完成

     

     

     

    参考:

    https://my.oschina.net/liyurong/blog/1929996

    展开全文
  • spring源码解读.xmind

    2020-08-04 13:49:27
    spring源码的脑图总结,源码解析清晰明了,结构罗列覆盖完整,一图直达,助您高效学习spring源码
  • springcloud 源码+解读

    2019-03-22 13:19:42
    springcloud 源码+解读springcloud 源码。 优秀的spring cloud源码。本人亲测完美运行。详细部署方案请参照我的博客11。 springcloud
  • Spring源码情操陶冶-ContextLoaderListener   ContextLoaderListener extends ContextLoader implements ServletContextListener contextInitialized --->initWebApplicationContext(); ApplicationContext...

    Spring源码情操陶冶-ContextLoaderListener 

     ContextLoaderListener extends ContextLoader implements ServletContextListener

    contextInitialized --->initWebApplicationContext();


    ApplicationContext体系:



    Spring源码情操陶冶-ContextLoader   

    WebApplicationContext initWebApplicationContext(ServletContext servletContext)  


    initWebApplicationContext方法里面有createWebApplicationContext方法 和configureAndRefreshWebApplicationContext 方法 。

    createWebApplicationContext创建一个空的WebApplicationContext(XmlWebApplicationContext),configureAndRefreshWebApplicationContext方法为WebApplicationContext读取相应的配置并且刷新context对象。


    configureAndRefreshWebApplicationContext方法包括指定contextConfigLocationSpring配置文件位置、给应用一个id倘若指定了contextId属性、 refresh()方法    ConfigurableWebApplicationContext.refresh()


    ConfigurableWebApplicationContext extends WebApplicationContext, ConfigurableApplicationContext 


    AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext, DisposableBean



    ConfigurableApplicationContext 接口有void refresh() throws BeansException, IllegalStateException;  抽象方法。

    只有一个实现类实现了方法 


    所以 ConfigurableWebApplicationContext.refresh() 调用的是 AbstractApplicationContext的refresh()方法。

    Spring源码情操陶冶-AbstractApplicationContext   refresh() 

    refresh里面有这几个方法:

    • AbstractApplicationContext#prepareRefresh
      刷新准备工作,@prepareRefresh

    • AbstractApplicationContext#obtainFreshBeanFactory
      涉及解析spring配置文件并封装为BeanDefinition对象保存至beanFactory中,@obtainFreshBeanFactory

    • AbstractApplicationContext#prepareBeanFactory
      beanFactory的准备工作,设置context的属性配置,@prepareBeanFactory

    • AbstractApplicationContext#postProcessBeanFactory
      主要添加ServletContextAwareProcessor处理类,@postProcessBeanFactory

    • AbstractApplicationContext#invokeBeanFactoryPostProcessors
      执行BeanDefinitionRegistryPostProcessors/BeanFactoryPostProcessors相关beans,@invokeBeanFactoryPostProcessors

    • AbstractApplicationContext#registerBeanPostProcessors
      注册所有实现BeanPostProcessor的接口bean到beanFactory的内部属性beanPostProcessors集合中,@registerBeanPostProcessors

    • AbstractApplicationContext#initMessageSource
      初始化资源配置,@initMessageSource

    • AbstractApplicationContext#initApplicationEventMulticaster
      初始化ApplictionEventMulticaster广播事件类,@initApplicationEventMulticaster

    • AbstractApplicationContext#onRefresh
      初始化themeSource,@onRefresh

    • AbstractApplicationContext#registerListeners
      注册ApplicationListener beans到ApplictionEventMulticaster广播集合,@registerListeners

    • AbstractApplicationContext#finishBeanFactoryInitialization
      实例化所有的非lazy-init类型的beans,@finishBeanFactoryInitialization

    • AbstractApplicationContext#finishRefresh
      完成刷新,并执行ContextRefreshedEvent事件,该事件涉及spring mvc,@finishRefresh


    Spring的BeanFactoryPostProcessor和BeanPostProcessor  

    finishBeanFactoryInitialization() preInstantiateSingletons()  getBean() doCreateBean()  initializeBean()


    configureAndRefreshWebApplicationContext方法之后WebApplicationContext对象已经完成 


    WebApplicationContext对象赋给servletContext:

    servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,this.context);


    至此,initWebApplicationContext完成。


    展开全文
  • spring源码解读
  • Spring源码解读

    2021-08-31 09:41:42
    第一章 Spring源码解读 spring是如何解决循环依赖的? 添加链接描述 总结:Spring将对象完整初始化过程分为了三步,createBeanInstance对象实例化 ⇒ populateBean对象属性填充 ⇒ initializeBean对象初始化。 ...

    第一章 Spring源码解读

    <parent>
    	<groupId>org.springframework.boot</groupId>
    	<artifactId>spring-boot-starter-parent</artifactId>
    	<version>2.1.0.RELEASE</version>
    </parent>
    
    1. spring容器与web容器:
    • spring容器:org.springframework.context.ApplicationContext;
    • web容器:javax.servlet.ServletContext(org.apache.catalina.core.ApplicationContext implements ServletContext)。
    1. ContextLoaderListener的作用?
      ContextLoaderListener作为一个中间者用来建立spring容器与web容器间的关系,真正起作用的是 ContextLoader。ContextLoader主要用于创建spring容器WebApplicationContext,并绑定web.xml中的contextConfigLocation所指定的spring配置文件,最后调用AbstractApplicationContext.refresh方法完成spring容器的各个核心组件的创建。
    public class ContextLoader {
       public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
       	if (this.context == null) {
       		this.context = createWebApplicationContext(servletContext);
       	}
       	if (this.context instanceof ConfigurableWebApplicationContext) {
       		configureAndRefreshWebApplicationContext(cwac, servletContext);
       	}
       }
       
       protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
       	String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
       	if (configLocationParam != null) {
       		wac.setConfigLocation(configLocationParam);
       	}
       	wac.refresh();
       }
    }
    
    public abstract class AbstractApplicationContext extends DefaultResourceLoader{
    
       public void refresh() throws BeansException, IllegalStateException {
       	// Allows post-processing of the bean factory in context subclasses.
       	postProcessBeanFactory(beanFactory);
       	// Invoke factory processors registered as beans in the context.
       	invokeBeanFactoryPostProcessors(beanFactory);
       	// Register bean processors that intercept bean creation.
       	registerBeanPostProcessors(beanFactory);
       	// Initialize message source for this context.
       	initMessageSource();
       	// Initialize event multicaster for this context.
       	initApplicationEventMulticaster();
       	// Initialize other special beans in specific context subclasses.
       	onRefresh();
       	// Check for listener beans and register them.
       	registerListeners();
       	// Instantiate all remaining (non-lazy-init) singletons.
       	finishBeanFactoryInitialization(beanFactory);
       	// Last step: publish corresponding event.
       	finishRefresh();
       }
       
       protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
       	// beanFactory ⇒ DefaultListableBeanFactory 
       	beanFactory.preInstantiateSingletons();
       }
    
    }
    
    1. Spring AOP的实现:
    • 首先创建一个BeanPostProcessor接口的实现类AnnotationAwareAspectJAutoProxyCreator对象,将其添加到AbstractBeanFactory的beanPostProcessors容器中;
    • 当调用createBean时(createBean调用doCreateBean),都会调用DefaultListableBeanFactory.resolveBeforeInstantiation方法对Bean对象做前置处理。此时便会调用到AnnotationAwareAspectJAutoProxyCreator.postProcessBeforeInstantiation()方法检查当前对象是否在切入点表达式的拦截范围内;
    • 如果在则根据通知,为该bean对象创建对应的代理对象并直接返回(跳过doCreateBean)。优先使用JDK动态代理,如果proxyTargetClass属性值为true或者目标类没有实现接口,就使用CGLib动态代理。
    public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
    		implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
    		
    	public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
    		Object cacheKey = getCacheKey(beanClass, beanName);
    
    		if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
    			if (this.advisedBeans.containsKey(cacheKey)) {
    				return null;
    			}
    			if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
    				this.advisedBeans.put(cacheKey, Boolean.FALSE);
    				return null;
    			}
    		}
    		TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
    		if (targetSource != null) {
    			if (StringUtils.hasLength(beanName)) {
    				this.targetSourcedBeans.add(beanName);
    			}
    			Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
    			Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
    			this.proxyTypes.put(cacheKey, proxy.getClass());
    			return proxy;
    		}
    		return null;
    	}
    }
    
    1. spring IOC容器初始化:
    • spring用BeanDefinition描述一个Bean元数据对象,包括这个Bean的lazy、scope、构造函数参数列表等信息;
    • AbstractApplicationContext的invokeBeanFactoryPostProcessors()方法调用ClassPathBeanDefinitionScanner.doScan();
    • 注解Bean、XML Bean都由doScan()方法来完成Bean的扫描:
      • findCandidateComponents(),递归查找指定包下的Component;
      • postProcessBeanDefinition(),为BeanDefinition设置配置属性(@Primary、@Lazy、@DependOn);
      • registerBeanDefinition(),将BeanDefinition注册到DefaultListableBeanFactory的beanDefinitionMap。
    public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {
    	protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
    		for (String basePackage : basePackages) {
    			Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
    			for (BeanDefinition candidate : candidates) {
    				postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
    				registerBeanDefinition(definitionHolder, this.registry);
    			}
    		}
    		return beanDefinitions;
    	}
    }
    
    • 最终,AbstractApplicationContext调用finishBeanFactoryInitialization()方法,对BeanDefinition容器中的所有非Lazy的单例对象初始化。
    public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory{
    		public void preInstantiateSingletons() throws BeansException {
    			List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
    			// Trigger initialization of all non-lazy singleton beans...
    			for (String beanName : beanNames) {
    				RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
    				if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
    					getBean(beanName);
    				}
    			}
    		}
    }
    
    1. spring是如何解决循环依赖的?
      Spring-bean的循环依赖以及解决方式
      框架源码专题:SPRING是如何解决循环依赖的?为什么无法解决多例和构造器的循环依赖

      总结:Spring只能处理通过属性注入或者setter注入的Bean,构造函数注入Bean的循环依赖无法处理。
    • AbstractBeanFactory创建主Bean对象时,调用AbstractAutowireCapableBeanFactory.doCreateBean()方法;
    • doCreateBean()方法会先调用createBeanInstance()方法,创建主Bean的实例(利用反射constructor.newInstance()方法);
    • 然后调用addSingletonFactory()方法,将主Bean的单例工厂(如果需要提前引用主Bean,则调用单例工厂的后置处理器beanPostProcessors)保存到三级缓存singletonFactories;
    • 接着调用populateBean()方法对主bean进行属性注入或者setter注入。此时,被注入的Bean可以从三级缓存singletonFactories中获取主Bean,并提前对其初始化后放入二级缓存放入earlySingletonObjects,然后访问或使用主Bean,这样被注入的Bean也是一个完整的对象,从而解决了循环依赖问题。
    • 最后,doCreateBean()方法执行完毕后,调用DefaultSingletonBeanRegistry.addSingleton()方法。将单例bean对象放入一级缓存singletonObjects中,并移除存放提前曝光对象的二级缓存earlySingletonObjects和该bean对象的创建工厂缓存singletonFactories。
    public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
    		implements AutowireCapableBeanFactory {
        protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
    			throws BeanCreationException {
    		// 第一步:实例化bean
    		instanceWrapper = createBeanInstance(beanName, mbd, args);
    		// 为Bean对象绑定后置处理器
    		applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
    		// 为避免后期循环依赖,提前曝露ObjectFactory到第三级缓存中。
    		addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
            // 第二步:填充属性
    		populateBean(beanName, mbd, instanceWrapper);
    		// 第三步:执行初始化逻辑
    		exposedObject = initializeBean(beanName, exposedObject, mbd);
    	}
    }
    
    public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
    
    	/** Cache of singleton objects: bean name --> bean instance,已经完成初始化的对象(一级缓存) */
    	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
    	/** Cache of early singleton objects: bean name --> bean instance,提前曝光的对象(二级缓存) */
    	private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
    	/** Cache of singleton factories: bean name --> ObjectFactory,提前曝光对象的后置处理器,当对象被提前曝光且被提前引用时才触发后置处理器(三级缓存)  */
    	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
    
    	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    	    Object singletonObject = this.singletonObjects.get(beanName);
    	    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
    	        synchronized (this.singletonObjects) {
    	            singletonObject = this.earlySingletonObjects.get(beanName);
    	            if (singletonObject == null && allowEarlyReference) {
    	                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
    	                if (singletonFactory != null) {
    	                    singletonObject = singletonFactory.getObject();
    	                    this.earlySingletonObjects.put(beanName, singletonObject);
    	                    this.singletonFactories.remove(beanName);
    	                }
    	            }
    	        }
    	    }
    	    return (singletonObject != NULL_OBJECT ? singletonObject : null);
    	}
    }
    
    1. @PostConstruct、@PreDestroy注、@Resource注解的实现:
    • 当对象实例化完成后属性填充前,会调用DefaultListableBeanFactory.applyMergedBeanDefinitionPostProcessors()方法,然后调用CommonAnnotationBeanPostProcessor.findLifecycleMetadata()方法将当前Bean对象中所有标注了@PostConstruct、@PreDestroy的方法和成员变量保存到LifecycleMetadata对象中;
    • 然后把LifecycleMetadata对象存入lifecycleMetadataCache容器;
    • 在populateBean阶段,调用postProcessProperties完成对@Resource注解的扫描,并注入值
    • 最终,当对象实例化、属性填充完成后的初始化阶段(initializeBean),调用AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization() ⇒ CommonAnnotationBeanPostProcessor.invokeInitMethods()调用LifecycleMetadata封装的当前对象的标注了@PostConstruct注解的方法。
    • 当Spring容器关闭的时候,AbstractApplicationContext.doClose() ⇒ DefaultListableBeanFactory.destroySingletons() ⇒ DisposableBeanAdapter.destroy() ⇒ CommonAnnotationBeanPostProcessor.invokeDestroyMethods()。
    1. @Autowired、@Value和@Inject注解的实现:
    • 同上,不过是在populateBean阶段,调用postProcessProperties方法,然后调用AutowiredAnnotationBeanPostProcessor.postProcessProperties()完成InjectionMetadata对象的封装,然后放入injectionMetadataCache缓存
    • @Resource优先byName,@Autowired和@Inject优先byName。
    1. HandlerMapping的设计与实现?
    • 在doCreateBean的initializeBean阶段,会调用AbstractHandlerMethodMapping的detectHandlerMethods方法;
    • detectHandlerMethods首先会获取bean中所有方法的Method和RequestMappingInfo对应关系,然后将RequestMappingInfo注册到AbstractHandlerMethodMapping的mappingRegistry容器中;
    • 最终当StandardWrapper触发initServlet()方法时,会调用DispatcherServlet的initHandlerMappings()方法,将mappingRegistry容器放入DispatcherServlet的handlerMappings集合中,等待后续getHandler。
    public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
    	protected void detectHandlerMethods(Object handler) {
    		Class<?> handlerType = (handler instanceof String ?
    				obtainApplicationContext().getType((String) handler) : handler.getClass());
    		if (handlerType != null) {
    			Class<?> userType = ClassUtils.getUserClass(handlerType);
    			Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
    					(MethodIntrospector.MetadataLookup<T>) method -> {
    						try {
    							return getMappingForMethod(method, userType);
    						}
    						catch (Throwable ex) {
    							throw new IllegalStateException("Invalid mapping on handler class [" +
    									userType.getName() + "]: " + method, ex);
    						}
    					});
    			methods.forEach((method, mapping) -> {
    				Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
    				registerHandlerMethod(handler, invocableMethod, mapping);
    			});
    		}
    	}
    }
    
    1. DispatcherServlet的设计与实现?
    • 当客户端向服务端发送一个http请求,经过过滤器链最终到达DispatcherServlet的doDispatch()方法;
    • doDispatch调用getHandler()获取一个与请求URL相映射的处理器映射器对象HandlerMapping;
    • doDispatch再调用getHandlerAdapter()获取一个处理器适配器对象HandlerAdapter,并调用处理器适配器的handle()方法处理请求,最终返回一个ModelAndView对象;
    • doDispatch最后调用processDispatchResult方法内的render方法,通过视图解析器对象ViewResolver将ModelAndView解析成一个视图对象View;
    • 最终通过response.getWriter().append(builder.toString())将View渲染到Response中。
      在这里插入图片描述
    public class DispatcherServlet extends FrameworkServlet {
    
       protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
       	HttpServletRequest processedRequest = request;
       	HandlerExecutionChain mappedHandler = null;
       	ModelAndView mv = null;
       	Exception dispatchException = null;
       	mappedHandler = getHandler(processedRequest);
       	HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
       	mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
       	processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
       }
    }
    

    第一章 总结

    AbstractApplicationContext.refresh()
    	=> invokeBeanFactoryPostProcess()
    			// IOC容器初始化
    		==> ClasspathBeanDefinitionScan.doScan()	
    				 // 查找指定包下的BeanDefinition对象(注解Bean、XML Bean)
    			===> findCandidateComponents()	
    				 // 处理BeanDefinition对象的元数据,包括@Lazy、@Primary、构造函数参数等
    			===> postProcessBeanDefinition()
    				 // 将BeanDefinition对象注册到DefaultListableBeanFactory的beanDefinitionNames集合
    			===> registerBeanDefinition()	
    			
    	   // 对所有的非Lazy的单例对象初始化	
    	=> finishBeanFactoryInitialization()	
    		    // 遍历beanDefinitionNames集合,调用getBean()对所有的BeanDefinition进行初始化
    		==> DefaultListableBeanFactory.preInstantiateSingletons()	
    			===> AbstractAutowireCapableBeanFactory.createBean()
    				// 对待初始化的Bean进行前置处理
    				====> resolveBeforeInstantiation()	
    					// AOP,检查待创建的Bean对象是否满足切入点表达式,若满足则创建代理对象
    					=====> AnnotationAwareAspectJAutoProxyCreator.postProcessBeforeInstantiation()	
    				====> doCreateBean() 
    					// 对象实例创建,使用反射constructor.newInstance()
    					=====> createBeanInstance()	
    					// 处理Bean对象的@PostConstruct、@PreDestroy、@Autowired、@Resource、@Inject等注解
    					=====> applyMergedBeanDefinitionPostProcessors()	
    						// 查找@PostConstruct、@PreDestroy、@Resource注解,并生成InjectionMetadata对象,
    						//存入CommonAnnotationBeanPostProcessor.injectionMetadataCache容器中
    						======> CommonAnnotationBeanPostProcessor.findResourceMetadata()	 
    						// 查找@Autowired、@Value、@Inject注解,并生成InjectionMetadata对象,
    						//存入AutowiredAnnotationBeanPostProcessor.injectionMetadataCache容器中
    						======> AutowiredAnnotationBeanPostProcessor.findAutowiringMetadata()	
    					// 将主Bean的单例工厂保存到三级缓存DefaultSingletonBeanRegistry.singletonFactories
    					//(如果需要提前引用主Bean,则调用单例工厂的后置处理器beanPostProcessors)
    					=====> addSingletonFactory()	
    					// 对象属性填充,对主bean进行属性注入或者setter注入。被注入的Bean可以从三级
    					//缓存singletonFactories中获取主Bean,并提前对其初始化后放入二级缓存放入earlySingletonObjects,
    					//然后访问或使用主Bean,这样被注入的Bean也是一个完整的对象,从而解决了循环依赖问题
    					=====> populateBean()	
    						======> InjectionMetadata.inject()	
    					// 对象初始化	
    					=====> initializeBean() 
    						// 调用当前Bean中所有标注了@PostConstruct的方法
    						======> CommonAnnotationBeanPostProcessor.invokeInitMethods()	
    
    	=> finishRefresh()	
    		// 将单例Bean放入一级缓存singletonObjects中,并移除存放提前曝光对象的二级缓存
    		//earlySingletonObjects和该bean对象的创建工厂缓存singletonFactories
    		DefaultSingletonBeanRegistry.addSingleton()	
    

    第二章 FAQ

    1. spring事务失效的条件?
      spring事务失效1
      spring事务失效2
      Spring事务失效的 8 大原因
      Spring 如何在一个事务中开启另一个事务?
    2. spring事务原理?
      spring事务原理
    3. spring setter注入与构造函数注入?
    • setter注入:发生在populateBean阶段,调用applyPropertyValues方法,完成注入;
    • 构造函数注入:发生在createBeanInstance阶段,调用ConstructorResolver.autowireConstructor方法,先为被注入的bean完成初始化,接着调用constructor.newInstance(args)完成主bean的初始化。若产生循环依赖问题,则注入失败,程序报错。
    展开全文
  • spring 源码解读

    2021-04-01 11:15:12
    springSpring 简介:要整咋就整大的,Spring Ioc 整体实现走一走:从创建容器走起: Spring 简介: Spring 是一个轻量级的容器框架,它帮助我门去管理对象的生命周期。 For example:spring就是一个托管中心,bean...

    Spring 简介:

    Spring 是一个轻量级的容器框架,它帮助我门去管理对象的生命周期。
    For example:spring就是一个托管中心,bean就是小baby,早上我们把小baby送到托管中心,晚上就接回来。中间吃饭,睡觉,上课,我们都不用操心。在spring中也是如此,我们只需要把bean在配置文件定义好,spring就会帮我们创建好对象,管理对象的生命周期,而我们只需要摸摸蹭亮蹭亮的脑阔直接拿对象用就行了。是不是瞬间就觉得spring so easy 呀,确实spring不过如此。
    在这里插入图片描述
    咳咳,逼装完了,下面我们就来说道说道Spring的核心 IocAop

    要整咋就整大的,Spring Ioc 整体实现走一走:

    工欲善其事必先利其器,在走代码之前,我们必须先了解spring ioc 管理Bean的整个流程。来呀,小二上图:
    在这里插入图片描述
    这就来!!!
    在这里插入图片描述

    从上面的图我们可以清晰的知道Spring ico 的一整套流程了,下面我们就来开始盘它吧!

    从创建容器走起:

    从容器中拿Bean,我们首先要创建Spring容器对象,ApplicationContext两个具体实现类是ClassPathXmlApplciationContext和FileSystemXmlApplicationContext,前面是根据ClassPath路径加载文件,后者是系统绝对路径,后者换环境还要改路径不方便。

    //1.查看ClassPathXmlApplicationContext 构造时做了什么
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("service.xml");
    ServiceA serviceA = applicationContext.getBean("serviceA",ServiceA.class);
    
    
    //ClassPathXmlApplicationCOntext容器构造是接受多个String 文件路径
    public ClassPathXmlApplicationContext(String... configLocations) throws BeansException {
            //this方法是调用了另外一个构造
            this(configLocations, true, (ApplicationContext)null);
        }  
       
     //接受了一个路径数组,一个标志位,还有一个空值         
    public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
            //查看下父类做了什么操作
            super(parent);
            this.setConfigLocations(configLocations);
            if (refresh) {
                this.refresh();
            }
    
        }
    //跑到AbstractApplicationContext这个抽象容器父类来实现一些操作  
     public AbstractApplicationContext(ApplicationContext parent) {
            //看下this()做了哪些初始化
            this();
            this.setParent(parent);
        }  
    public AbstractApplicationContext() {
            this.logger = LogFactory.getLog(this.getClass());
            this.id = ObjectUtils.identityToString(this);
            this.displayName = ObjectUtils.identityToString(this);
            //初始化一个beanFactory工厂扩展的集合
            this.beanFactoryPostProcessors = new ArrayList();
            //创建两个原子标志位
            this.active = new AtomicBoolean();
            this.closed = new AtomicBoolean();
            //创建一个观察者
            this.startupShutdownMonitor = new Object();
            //创建一个事件监听者集合
            this.applicationListeners = new LinkedHashSet();
            //创建资源匹配解析器
            this.resourcePatternResolver =       this.getResourcePatternResolver();
        } 
    //    
    public void setParent(ApplicationContext parent) {
      //传过来的ApplicationContext是null,所以这里没有加载spring的环境Environment
            this.parent = parent;
            if (parent != null) {
                Environment parentEnvironment = parent.getEnvironment();
                if (parentEnvironment instanceof ConfigurableEnvironment) {
                    this.getEnvironment().merge((ConfigurableEnvironment)parentEnvironment);
                }
            }
        }
    //那此时我们就回到了AbstractApplicationContext构造的方法里面继续往下跳
    //这时,让我们see this.setConfigLocations(configLocations);做了什么
    public void setConfigLocations(String... locations) {
            if (locations != null) {
                Assert.noNullElements(locations, "Config locations must not be null");
                this.configLocations = new String[locations.length];
    
                for(int i = 0; i < locations.length; ++i) {
                //调用resolvePath()将配置文件进行解析,加入到Spring环境中
                    this.configLocations[i] = this.resolvePath(locations[i]).trim();
                }
            } else {
                this.configLocations = null;
            }
        }
        //解析文件
        protected String resolvePath(String path) {
            //获取环境对象解析文件
            return this.getEnvironment().resolveRequiredPlaceholders(path);
        }
        public ConfigurableEnvironment getEnvironment() {
        //环境对象为null时,创建一个环境对象
            if (this.environment == null) {
                this.environment = this.createEnvironment();
            }
    
            return this.environment;
        }
        protected ConfigurableEnvironment createEnvironment() {
        //生成一个标准的环境对象
            return new StandardEnvironment();
        }
        
        //标准环境对象就定义了几个常量
        public class StandardEnvironment extends AbstractEnvironment {
        public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";
        public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";
    
        public StandardEnvironment() {
        }
    }
     
     //接下来回到resolveRequiredPlaceholders()方法
     public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
            if (this.strictHelper == null) {
                //创建一个文件属性占位符辅助对象,听起来咋还有点懵,来,盘它,看下它是做什么的。
                this.strictHelper = this.createPlaceholderHelper(false);
            }
    
            return this.doResolvePlaceholders(text, this.strictHelper);
        }
    //创建PropertyPlaceholderHelper对象  
    private PropertyPlaceholderHelper createPlaceholderHelper(boolean ignoreUnresolvablePlaceholders) {
    //咦,PorpertyPlaceholderHelper构造还接受了四个参数,让我们see有什么名堂,来,盘它。
    //仔细一看属性,wc发现不得了的事情。下面的前缀和后缀是不是很有印象,不错就是我们取系统定义变量时所用的占位符呀
    //private String placeholderPrefix = "${";
    //private String placeholderSuffix = "}";
    //private String valueSeparator = ":";
    //ignoreUnresolvablePlaceholders  这个是用来标记是否忽略不能解析的占位符。
    return new PropertyPlaceholderHelper(this.placeholderPrefix, this.placeholderSuffix, this.valueSeparator, ignoreUnresolvablePlaceholders);
        }
    //看到这是不是非常的亢奋呀,是不是瞬间就觉得自己发现了个大宝贝。没错,下面就是有大宝贝,来,接着盘。
    
    //这里就是做了一些简单的初始化
    public PropertyPlaceholderHelper(String placeholderPrefix, String placeholderSuffix, String valueSeparator, boolean ignoreUnresolvablePlaceholders) {
            Assert.notNull(placeholderPrefix, "'placeholderPrefix' must not be null");
            Assert.notNull(placeholderSuffix, "'placeholderSuffix' must not be null");
            this.placeholderPrefix = placeholderPrefix;
            this.placeholderSuffix = placeholderSuffix;
            String simplePrefixForSuffix = (String)wellKnownSimplePrefixes.get(this.placeholderSuffix);
            if (simplePrefixForSuffix != null && this.placeholderPrefix.endsWith(simplePrefixForSuffix)) {
                this.simplePrefix = simplePrefixForSuffix;
            } else {
                this.simplePrefix = this.placeholderPrefix;
            }
    
            this.valueSeparator = valueSeparator;
            this.ignoreUnresolvablePlaceholders = ignoreUnresolvablePlaceholders;
        }
    // 上面已经创建了文件属性的解析的对象,接下来就到了见证奇迹的时候了
    //回到 doResolvePlaceholders()方法,在spring中do开头的方法才是真正干活的方法
     private String doResolvePlaceholders(String text, PropertyPlaceholderHelper helper) {
            return helper.replacePlaceholders(text, new PlaceholderResolver() {
                public String resolvePlaceholder(String placeholderName) {
                    return AbstractPropertyResolver.this.getPropertyAsRawString(placeholderName);
                }
            });
        }
     //下面就是把文件的属性解析出来   
    public String replacePlaceholders(String value, PropertyPlaceholderHelper.PlaceholderResolver placeholderResolver) {
            Assert.notNull(value, "'value' must not be null");
            return this.parseStringValue(value, placeholderResolver, new HashSet());
        }
        protected String parseStringValue(String strVal, PropertyPlaceholderHelper.PlaceholderResolver placeholderResolver, Set<String> visitedPlaceholders) {
            StringBuilder result = new StringBuilder(strVal);
            int startIndex = strVal.indexOf(this.placeholderPrefix);
    
            while(startIndex != -1) {
                int endIndex = this.findPlaceholderEndIndex(result, startIndex);
                if (endIndex != -1) {
                    String placeholder = result.substring(startIndex + this.placeholderPrefix.length(), endIndex);
                    String originalPlaceholder = placeholder;
                    if (!visitedPlaceholders.add(placeholder)) {
                        throw new IllegalArgumentException("Circular placeholder reference '" + placeholder + "' in property definitions");
                    }
    
                    placeholder = this.parseStringValue(placeholder, placeholderResolver, visitedPlaceholders);
                    String propVal = placeholderResolver.resolvePlaceholder(placeholder);
                    if (propVal == null && this.valueSeparator != null) {
                        int separatorIndex = placeholder.indexOf(this.valueSeparator);
                        if (separatorIndex != -1) {
                            String actualPlaceholder = placeholder.substring(0, separatorIndex);
                            String defaultValue = placeholder.substring(separatorIndex + this.valueSeparator.length());
                            propVal = placeholderResolver.resolvePlaceholder(actualPlaceholder);
                            if (propVal == null) {
                                propVal = defaultValue;
                            }
                        }
                    }
    
                    if (propVal != null) {
                        propVal = this.parseStringValue(propVal, placeholderResolver, visitedPlaceholders);
                        result.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal);
                        if (logger.isTraceEnabled()) {
                            logger.trace("Resolved placeholder '" + placeholder + "'");
                        }
    
                        startIndex = result.indexOf(this.placeholderPrefix, startIndex + propVal.length());
                    } else {
                        if (!this.ignoreUnresolvablePlaceholders) {
                            throw new IllegalArgumentException("Could not resolve placeholder '" + placeholder + "'" + " in string value \"" + strVal + "\"");
                        }
    
                        startIndex = result.indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.length());
                    }
    
                    visitedPlaceholders.remove(originalPlaceholder);
                } else {
                    startIndex = -1;
                }
            }
    
            return result.toString();
        }   
     
    //接下来就是spring最核心的部分,上面已经把环境创建好了。setConfigLocations其实就是解析配置文件,创建好spring环境。下面我们来瞧一瞧spring的核心方法refresh();
    public void refresh() throws BeansException, IllegalStateException {
            synchronized(this.startupShutdownMonitor) {
                this.prepareRefresh();
                //创建默认工厂对象(核心)
                ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
                //设置工厂需要的属性
                this.prepareBeanFactory(beanFactory);
    
                try {   
                    //扩展方法     
                    this.postProcessBeanFactory(beanFactory);
                    //执行BeanFactoryPostProecessor扩展(核心)
                    this.invokeBeanFactoryPostProcessors(beanFactory);
                    //执行BeanPostProcessor扩展(核心)
                    this.registerBeanPostProcessors(beanFactory);
                    //国际化
                    this.initMessageSource();
                    //spring广播事件
                    this.initApplicationEventMulticaster();
                    //扩展
                    this.onRefresh();
                    //注册监听
                    this.registerListeners();
                    //实例化Bean(核心)
                    this.finishBeanFactoryInitialization(beanFactory);
                   //容器的收尾工作
                    this.finishRefresh();
                } catch (BeansException var5) {
                    if (this.logger.isWarnEnabled()) {
                        this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var5);
                    }
                    this.destroyBeans();
                    this.cancelRefresh(var5);
                    throw var5;
                }
    
            }
        }
    
    //先看prepareRefresh()方法
    protected void prepareRefresh() {
    //这里只是获取了下系统事件,设置了下原子变量值
            this.startupDate = System.currentTimeMillis();
            this.closed.set(false);
            this.active.set(true);
            if (this.logger.isInfoEnabled()) {
                this.logger.info("Refreshing " + this);
            }
    
            //这里就是上面画图BeanFactoryPostPorcessor,工厂BeanFactory进行自定义扩展的地方。可以进行一些自己的增强
            this.initPropertySources();
            //验证一下环境的必要属性。
            this.getEnvironment().validateRequiredProperties();
        }
        protected void initPropertySources() {
        }   
    

    书到用时方恨少,spring果然博大精深。refresh()方法里实现细节颇多,这里就不一一走下去了。上面如果我的理解有误,欢迎大佬指点!果然人还是不能装逼,越往深处走,越感觉spring的强大。在这里插入图片描述
    原创不易,白嫖容易,各位看官给个呗!!
    接下来学习继续盘它,在这里插入图片描述

    展开全文
  • Spring源码解读顺序

    2018-10-17 09:53:58
    Spring源代码解析(一):IOC容器:http://www.javaeye.com/topic/86339  Spring源代码解析(二):IoC容器在Web容器中的启动:http://www.javaeye.com/topic/86594  Spring源代码解析(三):Spring...Spring源代码解...
  • 在前面的文章中spring源码解读系列(八)中,我们继续剖析了spring的核心refresh()方法中的registerBeanPostProcessors(beanFactory)(完成BeanPostProcessor的注册)和initMessageSource()(为上下文初始化message...
  • Spring 源码解读:IOC 原理之依赖注入,Bean 的创建过程,循环依赖解决尝试获取 getBean获取 Bean name尝试获取单例对象,处理循环依赖假如成功获取到对象检查后返回 Bean 对象假如没获取到对象,双亲向上寻找确实没...
  • 1、Spring的入门代码: AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); UserService userService = (UserService) context.getBean("userService"); ...
  • Spring中出现循环依赖的场景很多,有些场景Spring自动帮我们解决了,而有些场景需要我们自己去解决。 Spring中Bean的生命周期 被Spring管理的对象叫做Bean,Bean的生成步骤: Spring扫描class得到BeanDefinition ...
  • 最新Spring源码解读与设计详析完整     下载地址:百度网盘
  • 文章目录前言一、使用传统方式观察者模式二、源码解读1.引入库2.读入数据总结 前言 要想代码写得好,设计模式不可少。 Spring框架启动过程中,有两个设计模式使用较多,一个是观察者模式,一个是processor处理时用...
  • 一、概述 对于大多数第一次看spring源码的人来说,都会感觉不知从哪开始看起,因为spring项目源码由多个子项目组成,如spring-beans,spring-context,spring-core,spring-aop,spring-web,spring-webmvc等,整个...
  • 文章目录前言一、一个简单的小例子二、源码解读1. 注入2. 使用逻辑总结 前言 有时候我们会在属性注入的时候添加@Lazy注解实现延迟注入,今天咱们通过阅读源码来分析下原因 一、一个简单的小例子 代码如下: @...
  • onRefresh 是一个用户可扩展的方法,具体实现可以看下spring boot 后面如果能更新到spring boot 在细说
  • 图解Spring的循环依赖 前言 Spring的循环依赖是spring架构设计中比较精彩的一环,学习Spring的循环依赖设计,对我们进行业务架构设计还是很有裨益的。 这里通过debug介绍一下,spring如何通过三级缓存来实现循环依赖...
  • spring源代码的中文解析,让你更加了解spring内部机制,封装类的重用于重写。
  • registerListeners 是将各种实现了ApplicationListener 的监听器注册到 ApplicationEventMulticaster
  • 一、Spring体系 1.1、 Spring Core:即,Spring核心,它是框架最基础的部分,提供IOC和依赖注入特性 1.2、 Spring Context:即,Spring上下文容器,它是BeanFactory功能加强的一个子接口 1.3、 Spring Web:它提供...
  • Spring中依赖注入的方式 分为两种:手动注入、自动注入 手动注入 在XML中定义Bean时,就是手动注入,手动注入分为两种:set方法注入、构造方法注入 下面这种是通过set方法进行注入 <bean name="userService" ...
  • Spring源代码解析(一):IOC容器:http://www.javaeye.com/topic/86339Spring源代码解析(二):IoC容器在Web容器中的启动:http://www.javaeye.com/topic/86594Spring源代码解析(三):Spring JDBC:...Spri...
  • Spring源码解读——启动流程 准备工作 maven依赖 <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.7</...
  • spring源码解读系列(二)的最后我们发现了spring解析bean的方法分为两种,一种是解析spring工厂内部默认的标签,即import、alias、beans、bean;另一种是解析我们自定义的标签,本文详细分析spring解析自定义标签...
  • 直接看源码比较难的原因是代码枯燥不够形象。就像是练习剑法没有心法指导的话容易走火入魔。所以该系列讲解方式主要是指导思想。告诉你逻辑路线,然后让你主动的去探索。而不是以代码来讲代码。那样的话讲多少遍都是...
  • initApplicationEventMulticaster 初始化事件广播器 /** * Initialize the ApplicationEventMulticaster. ... * @see org.springframework.context.event.SimpleApplicationEventMulticaster */ pr.
  • ConfigurationClassPostProcessor 是spring注解注入bean的核心类,ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor 因此ConfigurationClassPostProcessor是...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 19,642
精华内容 7,856
关键字:

spring源码解读

spring 订阅