引言 新建一个 maven 工程,添加依赖:
1 2 3 4 5 6 <dependency > <groupId > org.springframework</groupId > <artifactId > spring-context</artifactId > <version > 5.1.1.RELEASE</version > </dependency >
定义一个接口:
1 2 3 public interface MessageService { String getMessage () ; }
实现该接口:
1 2 3 4 5 6 public class MessageServiceImpl implements MessageService { public String getMessage () { return "Hello" ; } }
在 resources 目录新建一个配置文件 application.xml
:
1 2 3 4 5 6 7 <?xml version="1.0" encoding="UTF-8" ?> <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" > <bean id ="messageService" class ="com.zoc.ioc.MessageServiceImpl" /> </beans >
主程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class App { public static void main (String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext ("classpath:application.xml" ); System.out.println("context 启动成功" ); MessageService messageService = context.getBean(MessageService.class); System.out.println(messageService.getMessage()); } }
ApplicationContext context = new ClassPathXmlApplicationContext(...)
就是在 ClassPath 中寻找 xml 配置文件,根据 xml 文件内容来构建 ApplicationContext。当然,除了 ClassPathXmlApplicationContext,我们还可以选择其他方法构建 ApplicationContext。
大体的继承结构:
我们可以使用绿色的 FileSystemXmlApplicationContext 和 AnnotationConfigApplicationContext 这两个类代替 ClassPathXmlApplicationContext:
BeanFactory 简介 BeanFactory:生产 Bean 的工厂,负责生产和管理各个 Bean 实例。
前面的 ApplicationContext 就是一个 BeanFactory。
和 BeanFactory 接口相关的继承结构:
ApplicationContext 继承了 ListableBeanFactory
,Listable 表示可以获取多个 Bean。看源码可以发现,最顶层 BeanFactory 接口的方法都只能获取单个 Bean。
ApplicationContext 继承了 HierarchicalBeanFactory
,Hierarchical 表示可以启动多个 BeanFactory,然后可以将各个 BeanFactory 设置为父子关系。
AutowireCapableBeanFactory
,Autowire 表示可以用来自动装配 Bean。仔细看上图可以发现 ApplicationContext 并没有继承它,不过不继承,不代表不使用,ApplicationContext 接口定义中的最后一个方法 getAutowireCapableBeanFactory() 就表示了可以获得该 BeanFactory。
ConfigurableListableBeanFactory
是一个特殊的接口,看图,特殊之处在于它继承了第二层所有的三个接口,而 ApplicationContext 没有。
启动过程分析 ClassPathXmlApplicationContext 构造方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext { private Resource[] configResources; public ClassPathXmlApplicationContext (ApplicationContext parent) { super (parent); } ... public ClassPathXmlApplicationContext (String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException { super (parent); setConfigLocations(configLocations); if (refresh) { refresh(); } } ... }
重点说 refresh()。
在 ApplicationContext 已经建立起来后,我们是可以通过调用 refresh() 这个方法重建的,refresh() 会将原来的 ApplicationContext 销毁,然后再重新执行一次初始化操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 @Override public void refresh () throws BeansException, IllegalStateException { synchronized (this .startupShutdownMonitor) { prepareRefresh(); ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); prepareBeanFactory(beanFactory); try { postProcessBeanFactory(beanFactory); invokeBeanFactoryPostProcessors(beanFactory); registerBeanPostProcessors(beanFactory); initMessageSource(); initApplicationEventMulticaster(); onRefresh(); registerListeners(); finishBeanFactoryInitialization(beanFactory); finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } destroyBeans(); cancelRefresh(ex); throw ex; } finally { resetCommonCaches(); } } }
创建 Bean 容器前的准备工作 refresh() 方法中的第一行 prepareRefresh()
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 protected void prepareRefresh () { this .startupDate = System.currentTimeMillis(); this .closed.set(false ); this .active.set(true ); if (logger.isDebugEnabled()) { if (logger.isTraceEnabled()) { logger.trace("Refreshing " + this ); } else { logger.debug("Refreshing " + getDisplayName()); } } initPropertySources(); getEnvironment().validateRequiredProperties(); this .earlyApplicationEvents = new LinkedHashSet <>(); }
创建 Bean 容器,加载并注册 Bean refresh() 方法中的下一行 obtainFreshBeanFactory()
。
注意,这个方法是全文最重要的部分之一,这里将会初始化 BeanFactory、加载 Bean、注册 Bean 等等。
这步结束后,Bean 实例还没生成。
1 2 3 4 5 6 protected ConfigurableListableBeanFactory obtainFreshBeanFactory () { refreshBeanFactory(); return getBeanFactory(); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 @Override protected final void refreshBeanFactory () throws BeansException { if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory); synchronized (this .beanFactoryMonitor) { this .beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException ("I/O error parsing bean definition source for " + getDisplayName(), ex); } }
为什么实例化 DefaultListableBeanFactory?
前面我们说了有个很特殊的接口 ConfigurableListableBeanFactory,它实现了 BeanFactory 下面一层的所有三个接口:
ConfigurableListableBeanFactory 只有一个实现类 DefaultListableBeanFactory,这个实现类还通过实现右边的 AbstractAutowireCapableBeanFactory 通吃了右路继承。
所以最底下这个 DefaultListableBeanFactory 基本上是最牛的 BeanFactory 了,这也是为什么这里会使用这个类来实例化的原因。
如果想在程序运行的时候动态往 IOC 容器中注册新的 Bean,就要使用到这个类。那我们怎么在运行时获得这个实例呢? 之前我们说过 ApplicationContext 接口能获取到 AutowireCapableBeanFactory,就是最右上角那个,把它向下转型就能得到 DefaultListableBeanFactory 了。
BeanDefinition 接口定义 这里的 BeanDefinition 就是 Spring 的 Bean。我们定义的各个 Bean 会转换成一个个 BeanDefinition 存在于 BeanFactory 中。
所以,如果有人问你 Bean 是什么的时候,你要知道 Bean 在代码层面上可以认为是 BeanDefinition 的实例。
BeanDefinition 中保存了我们的 Bean 信息,比如这个 Bean 指向的是哪个类、是否是单例的、是否懒加载、这个 Bean 依赖了哪些 Bean 等等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 public interface BeanDefinition extends AttributeAccessor , BeanMetadataElement { String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON; String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE; int ROLE_APPLICATION = 0 ; int ROLE_SUPPORT = 1 ; int ROLE_INFRASTRUCTURE = 2 ; void setParentName (String parentName) ; String getParentName () ; void setBeanClassName (String beanClassName) ; String getBeanClassName () ; void setScope (String scope) ; String getScope () ; void setLazyInit (boolean lazyInit) ; boolean isLazyInit () ; void setDependsOn (String... dependsOn) ; String[] getDependsOn(); void setAutowireCandidate (boolean autowireCandidate) ; boolean isAutowireCandidate () ; void setPrimary (boolean primary) ; boolean isPrimary () ; void setFactoryBeanName (String factoryBeanName) ; String getFactoryBeanName () ; void setFactoryMethodName (String factoryMethodName) ; String getFactoryMethodName () ; ConstructorArgumentValues getConstructorArgumentValues () ; MutablePropertyValues getPropertyValues () ; boolean isSingleton () ; boolean isPrototype () ; boolean isAbstract () ; int getRole () ; String getDescription () ; String getResourceDescription () ; BeanDefinition getOriginatingBeanDefinition () ; }
往下看 refreshBeanFactory() 方法中的剩余部分:
1 2 customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory);
customizeBeanFactory customizeBeanFactory(beanFactory) 比较简单,就是配置是否允许 BeanDefinition 覆盖、是否允许循环引用。
1 2 3 4 5 6 7 8 9 10 protected void customizeBeanFactory (DefaultListableBeanFactory beanFactory) { if (this .allowBeanDefinitionOverriding != null ) { beanFactory.setAllowBeanDefinitionOverriding(this .allowBeanDefinitionOverriding); } if (this .allowCircularReferences != null ) { beanFactory.setAllowCircularReferences(this .allowCircularReferences); } }
默认情况下,allowBeanDefinitionOverriding 属性为 null,在配置文件中定义 Bean 时使用了相同的 id 或 name,如果在同一配置文件中重复,会抛错;而如果不是同一配置文件中,会发生覆盖。
循环引用也很好理解:A 依赖 B,而 B 依赖 A。或 A 依赖 B,B 依赖 C,而 C 依赖 A。
默认情况下,Spring 允许循环依赖,当然如果你在 A 的构造方法中依赖 B,在 B 的构造方法中依赖 A 是不行的。
loadBeanDefinitions 接下来是最重要的 loadBeanDefinitions(beanFactory) 方法了,这个方法将根据配置,加载各个 Bean,然后放到 BeanFactory 中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @Override protected void loadBeanDefinitions (DefaultListableBeanFactory beanFactory) throws BeansException, IOException { XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader (beanFactory); beanDefinitionReader.setEnvironment(this .getEnvironment()); beanDefinitionReader.setResourceLoader(this ); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver (this )); initBeanDefinitionReader(beanDefinitionReader); loadBeanDefinitions(beanDefinitionReader); }
接下来用刚刚初始化的 Reader 开始来加载 xml 配置:(可以选择性跳过,不是很重要)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 protected void loadBeanDefinitions (XmlBeanDefinitionReader reader) throws BeansException, IOException { Resource[] configResources = getConfigResources(); if (configResources != null ) { reader.loadBeanDefinitions(configResources); } String[] configLocations = getConfigLocations(); if (configLocations != null ) { reader.loadBeanDefinitions(configLocations); } } @Override public int loadBeanDefinitions (Resource... resources) throws BeanDefinitionStoreException { Assert.notNull(resources, "Resource array must not be null" ); int counter = 0 ; for (Resource resource : resources) { counter += loadBeanDefinitions(resource); } return counter; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 @Override public int loadBeanDefinitions (Resource resource) throws BeanDefinitionStoreException { return loadBeanDefinitions(new EncodedResource (resource)); } public int loadBeanDefinitions (EncodedResource encodedResource) throws BeanDefinitionStoreException { Assert.notNull(encodedResource, "EncodedResource must not be null" ); if (logger.isInfoEnabled()) { logger.info("Loading XML bean definitions from " + encodedResource.getResource()); } Set<EncodedResource> currentResources = this .resourcesCurrentlyBeingLoaded.get(); if (currentResources == null ) { currentResources = new HashSet <EncodedResource>(4 ); this .resourcesCurrentlyBeingLoaded.set(currentResources); } if (!currentResources.add(encodedResource)) { throw new BeanDefinitionStoreException ( "Detected cyclic loading of " + encodedResource + " - check your import definitions!" ); } try { InputStream inputStream = encodedResource.getResource().getInputStream(); try { InputSource inputSource = new InputSource (inputStream); if (encodedResource.getEncoding() != null ) { inputSource.setEncoding(encodedResource.getEncoding()); } return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } finally { inputStream.close(); } } catch (IOException ex) { throw new BeanDefinitionStoreException ( "IOException parsing XML document from " + encodedResource.getResource(), ex); } finally { currentResources.remove(encodedResource); if (currentResources.isEmpty()) { this .resourcesCurrentlyBeingLoaded.remove(); } } } protected int doLoadBeanDefinitions (InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { Document doc = doLoadDocument(inputSource, resource); return registerBeanDefinitions(doc, resource); } catch (...) } 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; }
1 2 3 4 5 6 7 8 9 10 @Override public void registerBeanDefinitions (Document doc, XmlReaderContext readerContext) { this .readerContext = readerContext; logger.debug("Loading bean definitions" ); Element root = doc.getDocumentElement(); doRegisterBeanDefinitions(root); }
经过漫长的链路,一个配置文件终于转换为一颗 DOM 树了,注意,这里指的是其中一个配置文件,不是所有的,读者可以看到上面有个 for 循环的。
下面开始从根节点开始解析:
doRegisterBeanDefinitions 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 protected void doRegisterBeanDefinitions (Element root) { BeanDefinitionParserDelegate parent = this .delegate; this .delegate = createDelegate(getReaderContext(), root, parent); if (this .delegate.isDefaultNamespace(root)) { String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); if (StringUtils.hasText(profileSpec)) { String[] specifiedProfiles = StringUtils.tokenizeToStringArray( profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { if (logger.isInfoEnabled()) { logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + getReaderContext().getResource()); } return ; } } } preProcessXml(root); parseBeanDefinitions(root, this .delegate); postProcessXml(root); this .delegate = parent; }
preProcessXml(root) 和 postProcessXml(root) 是给子类用的钩子方法,鉴于没有被使用到,也不是我们的重点,直接跳过。
这里涉及到了 profile,不了解的可以在附录中参考一下。
接下来,看核心解析方法 parseBeanDefinitions(root, this.delegate)
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 protected void parseBeanDefinitions (Element root, BeanDefinitionParserDelegate delegate) { if (delegate.isDefaultNamespace(root)) { NodeList nl = root.getChildNodes(); for (int i = 0 ; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element) { Element ele = (Element) node; if (delegate.isDefaultNamespace(ele)) { parseDefaultElement(ele, delegate); } else { delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } }
从上面的代码,可以看到,对于每个配置来说,分别进入: parseDefaultElement(ele, delegate); 和 delegate.parseCustomElement(ele); 这两个分支。
parseDefaultElement(ele, delegate) 代表解析的节点是 <import />、<alias />、<bean />、<beans /> 这几个。
这里的四个标签之所以是 default 的,是因为它们是处于这个 namespace 下定义的:http://www.springframework.org/schema/beans
不熟悉 namespace 的请看下面贴出来的 xml:
1 2 3 4 5 6 <beans xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns ="http://www.springframework.org/schema/beans" xsi:schemaLocation =" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" default-autowire ="byName" >
对于其他的标签,将进入到 delegate.parseCustomElement(element) 这个分支。如我们经常会使用到的、、、等。 这些属于扩展,如果需要使用上面这些 ”非 default“ 标签,那么上面的 xml 头部的地方也要引入相应的 namespace 和 .xsd 文件的路径,如:
1 2 3 4 5 6 7 8 9 10 11 12 <beans xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns ="http://www.springframework.org/schema/beans" xmlns:context ="http://www.springframework.org/schema/context" xmlns:mvc ="http://www.springframework.org/schema/mvc" xsi:schemaLocation =" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd" default-autowire ="byName" >
同时代码中需要提供相应的 parser 来解析,如 MvcNamespaceHandler、TaskNamespaceHandler、ContextNamespaceHandler、AopNamespaceHandler 等。 假如读者想分析 <context:property-placeholder location=”classpath:xx.properties” /> 的实现原理,就应该到 ContextNamespaceHandler 中找答案。
回过神来,看看处理 default 标签的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 private void parseDefaultElement (Element ele, BeanDefinitionParserDelegate delegate) { if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { importBeanDefinitionResource(ele); } else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { processAliasRegistration(ele); } else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate); } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { doRegisterBeanDefinitions(ele); } }
这里只挑重点标签说。
processBeanDefinition 下面是 processBeanDefinition 解析 <bean /> 标签:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 protected void processBeanDefinition (Element ele, BeanDefinitionParserDelegate delegate) { BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null ) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'" , ele, ex); } getReaderContext().fireComponentRegistered(new BeanComponentDefinition (bdHolder)); } }
继续往下看怎么解析之前,我们先看下 <bean /> 标签中可以定义哪些属性:
Property 说明 class 类的全限定名 name 可指定 id、name(用逗号、分号、空格分隔) scope 作用域 constructor arguments 指定构造参数 properties 设置属性的值 autowiring mode no(默认值)、byName、byType、 constructor lazy-initialization mode 是否懒加载(如果被非懒加载的bean依赖了那么其实也就不能懒加载了) initialization method bean 属性设置完成后,会调用这个方法 destruction method bean 销毁后的回调方法
在 xml 上就是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <bean id ="exampleBean" name ="name1, name2, name3" class ="com.javadoop.ExampleBean" scope ="singleton" lazy-init ="true" init-method ="init" destroy-method ="cleanup" > <constructor-arg type ="int" value ="7500000" /> <constructor-arg name ="years" value ="7500000" /> <constructor-arg index ="0" value ="7500000" /> <property name ="beanOne" > <ref bean ="anotherExampleBean" /> </property > <property name ="beanTwo" ref ="yetAnotherBean" /> <property name ="integerProperty" value ="1" /> </bean >
当然,除了上面举例出来的这些,还有 factory-bean、factory-method、<lockup-method />、<replaced-method />、<meta />、<qualifier /> 这几个。
继续往里看怎么解析 bean 元素,是怎么转换到 BeanDefinitionHolder 的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 public BeanDefinitionHolder parseBeanDefinitionElement (Element ele) { return parseBeanDefinitionElement(ele, null ); } public BeanDefinitionHolder parseBeanDefinitionElement (Element ele, BeanDefinition containingBean) { String id = ele.getAttribute(ID_ATTRIBUTE); String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); List<String> aliases = new ArrayList <String>(); if (StringUtils.hasLength(nameAttr)) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS); aliases.addAll(Arrays.asList(nameArr)); } String beanName = id; if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) { beanName = aliases.remove(0 ); if (logger.isDebugEnabled()) { logger.debug("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases" ); } } if (containingBean == null ) { checkNameUniqueness(beanName, aliases, ele); } AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); if (beanDefinition != null ) { if (!StringUtils.hasText(beanName)) { try { if (containingBean != null ) { beanName = BeanDefinitionReaderUtils.generateBeanName( beanDefinition, this .readerContext.getRegistry(), true ); } else { beanName = this .readerContext.generateBeanName(beanDefinition); String beanClassName = beanDefinition.getBeanClassName(); if (beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && !this .readerContext.getRegistry().isBeanNameInUse(beanClassName)) { aliases.add(beanClassName); } } if (logger.isDebugEnabled()) { logger.debug("Neither XML 'id' nor 'name' specified - " + "using generated bean name [" + beanName + "]" ); } } catch (Exception ex) { error(ex.getMessage(), ele); return null ; } } String[] aliasesArray = StringUtils.toStringArray(aliases); return new BeanDefinitionHolder (beanDefinition, beanName, aliasesArray); } return null ; }
再看看怎么根据配置创建 BeanDefinition 实例的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 public AbstractBeanDefinition parseBeanDefinitionElement (Element ele, String beanName, BeanDefinition containingBean) { this .parseState.push(new BeanEntry (beanName)); String className = null ; if (ele.hasAttribute(CLASS_ATTRIBUTE)) { className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); } try { String parent = null ; if (ele.hasAttribute(PARENT_ATTRIBUTE)) { parent = ele.getAttribute(PARENT_ATTRIBUTE); } AbstractBeanDefinition bd = createBeanDefinition(className, parent); parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); parseMetaElements(ele, bd); parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); parseConstructorArgElements(ele, bd); parsePropertyElements(ele, bd); parseQualifierElements(ele, bd); bd.setResource(this .readerContext.getResource()); bd.setSource(extractSource(ele)); return bd; } catch (ClassNotFoundException ex) { error("Bean class [" + className + "] not found" , ele, ex); } catch (NoClassDefFoundError err) { error("Class that bean class [" + className + "] depends on not found" , ele, err); } catch (Throwable ex) { error("Unexpected failure during bean definition parsing" , ele, ex); } finally { this .parseState.pop(); } return null ; }
到这里,我们已经完成了根据 <bean /> 配置创建了一个 BeanDefinitionHolder 实例。注意,是一个。
回到解析 <bean /> 的入口方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 protected void processBeanDefinition (Element ele, BeanDefinitionParserDelegate delegate) { BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null ) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'" , ele, ex); } getReaderContext().fireComponentRegistered(new BeanComponentDefinition (bdHolder)); } }
这里已经根据一个 <bean /> 标签产生了一个 BeanDefinitionHolder 的实例,这个实例里面也就是一个 BeanDefinition 的实例和它的 beanName、aliases 这三个信息。
注意,我们的关注点始终在 BeanDefinition 上:
1 2 3 4 5 6 7 8 public class BeanDefinitionHolder implements BeanMetadataElement { private final BeanDefinition beanDefinition; private final String beanName; private final String[] aliases; ...
然后我们准备注册这个 BeanDefinition,最后,把这个注册事件发送出去。
注册 Bean 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public static void registerBeanDefinition (BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { String beanName = definitionHolder.getBeanName(); registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); String[] aliases = definitionHolder.getAliases(); if (aliases != null ) { for (String alias : aliases) { registry.registerAlias(beanName, alias); } } }
别名注册的放一边,毕竟它很简单,我们看看怎么注册 Bean:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 @Override public void registerBeanDefinition (String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { Assert.hasText(beanName, "Bean name must not be empty" ); Assert.notNull(beanDefinition, "BeanDefinition must not be null" ); if (beanDefinition instanceof AbstractBeanDefinition) { try { ((AbstractBeanDefinition) beanDefinition).validate(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException (...); } } BeanDefinition oldBeanDefinition; oldBeanDefinition = this .beanDefinitionMap.get(beanName); if (oldBeanDefinition != null ) { if (!isAllowBeanDefinitionOverriding()) { throw new BeanDefinitionStoreException (beanDefinition.getResourceDescription()... } else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) { } else if (!beanDefinition.equals(oldBeanDefinition)) { } else { } this .beanDefinitionMap.put(beanName, beanDefinition); } else { if (hasBeanCreationStarted()) { synchronized (this .beanDefinitionMap) { this .beanDefinitionMap.put(beanName, beanDefinition); List<String> updatedDefinitions = new ArrayList <String>(this .beanDefinitionNames.size() + 1 ); updatedDefinitions.addAll(this .beanDefinitionNames); updatedDefinitions.add(beanName); this .beanDefinitionNames = updatedDefinitions; if (this .manualSingletonNames.contains(beanName)) { Set<String> updatedSingletons = new LinkedHashSet <String>(this .manualSingletonNames); updatedSingletons.remove(beanName); this .manualSingletonNames = updatedSingletons; } } } else { this .beanDefinitionMap.put(beanName, beanDefinition); this .beanDefinitionNames.add(beanName); this .manualSingletonNames.remove(beanName); } this .frozenBeanDefinitionNames = null ; } if (oldBeanDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); } }
到这里已经初始化了 Bean 容器,<bean /> 配置也相应的转换为了一个个 BeanDefinition,然后注册了各个 BeanDefinition 到注册中心,并且发送了注册事件。
准备 Bean 容器:prepareBeanFactory 说到这里,我们回到 refresh() 方法,上面才说完 obtainFreshBeanFactory() 方法。
Spring 把我们在 xml 配置的 bean 都注册以后,会”手动”注册一些特殊的 bean。
这里简单介绍下 prepareBeanFactory(factory) 方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 protected void prepareBeanFactory (ConfigurableListableBeanFactory beanFactory) { beanFactory.setBeanClassLoader(getClassLoader()); beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver (beanFactory.getBeanClassLoader())); beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar (this , getEnvironment())); beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor (this )); beanFactory.ignoreDependencyInterface(EnvironmentAware.class); beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class); beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); beanFactory.ignoreDependencyInterface(MessageSourceAware.class); beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); beanFactory.registerResolvableDependency(ResourceLoader.class, this ); beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this ); beanFactory.registerResolvableDependency(ApplicationContext.class, this ); beanFactory.addBeanPostProcessor(new ApplicationListenerDetector (this )); if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor (beanFactory)); beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader (beanFactory.getBeanClassLoader())); } if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment()); } if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties()); } if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment()); } }
在上面这块代码中,Spring 对一些特殊的 bean 进行了处理,读者如果暂时还不能消化它们也没有关系,慢慢往下看。
初始化所有的 singleton beans 我们的重点是 finishBeanFactoryInitialization(beanFactory),这里会负责初始化所有的 singleton beans。
注意,后面的描述中,我都会使用初始化或预初始化来代表这个阶段,Spring 会在这个阶段完成所有的 singleton beans 的实例化。
我们来总结一下,到目前为止,应该说 BeanFactory 已经创建完成,并且所有的实现了 BeanFactoryPostProcessor 接口的 Bean 都已经初始化并且其中的 postProcessBeanFactory(factory) 方法已经得到回调执行了。而且 Spring 已经“手动”注册了一些特殊的 Bean,如 “environment”、“systemProperties” 等。
剩下的就是初始化 singleton beans 了,我们知道它们是单例的,如果没有设置懒加载,那么 Spring 会在接下来初始化所有的 singleton beans。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 protected void finishBeanFactoryInitialization (ConfigurableListableBeanFactory beanFactory) { if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) && beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) { beanFactory.setConversionService( beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)); } if (!beanFactory.hasEmbeddedValueResolver()) { beanFactory.addEmbeddedValueResolver(new StringValueResolver () { @Override public String resolveStringValue (String strVal) { return getEnvironment().resolvePlaceholders(strVal); } }); } String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false , false ); for (String weaverAwareName : weaverAwareNames) { getBean(weaverAwareName); } beanFactory.setTempClassLoader(null ); beanFactory.freezeConfiguration(); beanFactory.preInstantiateSingletons(); }
从上面最后一行往里看,我们就又回到 DefaultListableBeanFactory 这个类了,这个类大家应该都不陌生了吧。
preInstantiateSingletons 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 @Override public void preInstantiateSingletons () throws BeansException { if (this .logger.isDebugEnabled()) { this .logger.debug("Pre-instantiating singletons in " + this ); } List<String> beanNames = new ArrayList <String>(this .beanDefinitionNames); for (String beanName : beanNames) { RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { if (isFactoryBean(beanName)) { final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName); boolean isEagerInit; if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { isEagerInit = AccessController.doPrivileged(new PrivilegedAction <Boolean>() { @Override public Boolean run () { return ((SmartFactoryBean<?>) factory).isEagerInit(); } }, getAccessControlContext()); } else { isEagerInit = (factory instanceof SmartFactoryBean && ((SmartFactoryBean<?>) factory).isEagerInit()); } if (isEagerInit) { getBean(beanName); } } else { getBean(beanName); } } } for (String beanName : beanNames) { Object singletonInstance = getSingleton(beanName); if (singletonInstance instanceof SmartInitializingSingleton) { final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance; if (System.getSecurityManager() != null ) { AccessController.doPrivileged(new PrivilegedAction <Object>() { @Override public Object run () { smartSingleton.afterSingletonsInstantiated(); return null ; } }, getAccessControlContext()); } else { smartSingleton.afterSingletonsInstantiated(); } } } }
接下来,我们就进入到 getBean(beanName) 方法了,这个方法我们经常用来从 BeanFactory 中获取一个 Bean,而初始化的过程也封装到了这个方法里。
getBean 在继续前进之前,读者应该具备 FactoryBean 的知识,如果读者还不熟悉,请移步附录部分了解 FactoryBean。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 @Override public Object getBean (String name) throws BeansException { return doGetBean(name, null , null , false ); } @SuppressWarnings("unchecked") protected <T> T doGetBean ( final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException { final String beanName = transformedBeanName(name); Object bean; Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null ) { if (logger.isDebugEnabled()) { if (isSingletonCurrentlyInCreation(beanName)) { logger.debug("..." ); } else { logger.debug("Returning cached instance of singleton bean '" + beanName + "'" ); } } bean = getObjectForBeanInstance(sharedInstance, name, beanName, null ); } else { if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException (beanName); } BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { String nameToLookup = originalBeanName(name); if (args != null ) { return (T) parentBeanFactory.getBean(nameToLookup, args); } else { return parentBeanFactory.getBean(nameToLookup, requiredType); } } if (!typeCheckOnly) { markBeanAsCreated(beanName); } try { final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); checkMergedBeanDefinition(mbd, beanName, args); String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null ) { for (String dep : dependsOn) { if (isDependent(beanName, dep)) { throw new BeanCreationException (mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'" ); } registerDependentBean(dep, beanName); getBean(dep); } } if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, new ObjectFactory <Object>() { @Override public Object getObject () throws BeansException { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { destroySingleton(beanName); throw ex; } } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } else if (mbd.isPrototype()) { Object prototypeInstance = null ; try { beforePrototypeCreation(beanName); prototypeInstance = createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } else { String scopeName = mbd.getScope(); final Scope scope = this .scopes.get(scopeName); if (scope == null ) { throw new IllegalStateException ("No Scope registered for scope name '" + scopeName + "'" ); } try { Object scopedInstance = scope.get(beanName, new ObjectFactory <Object>() { @Override public Object getObject () throws BeansException { beforePrototypeCreation(beanName); try { return createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } } }); bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); } catch (IllegalStateException ex) { throw new BeanCreationException (beanName, "Scope '" + scopeName + "' is not active for the current thread; consider " + "defining a scoped proxy for this bean if you intend to refer to it from a singleton" , ex); } } } catch (BeansException ex) { cleanupAfterBeanCreationFailure(beanName); throw ex; } } if (requiredType != null && bean != null && !requiredType.isInstance(bean)) { try { return getTypeConverter().convertIfNecessary(bean, requiredType); } catch (TypeMismatchException ex) { if (logger.isDebugEnabled()) { logger.debug("Failed to convert bean '" + name + "' to required type '" + ClassUtils.getQualifiedName(requiredType) + "'" , ex); } throw new BeanNotOfRequiredTypeException (name, requiredType, bean.getClass()); } } return (T) bean; }
大家应该也猜到了,接下来当然是分析 createBean 方法:
1 protected abstract Object createBean (String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException;
第三个参数 args 数组代表创建实例需要的参数,不就是给构造方法用的参数,或者是工厂 Bean 的参数嘛,不过要注意,在我们的初始化阶段,args 是 null。
这回我们要到一个新的类了 AbstractAutowireCapableBeanFactory,看类名,AutowireCapable?类名是不是也说明了点问题了。
主要是为了以下场景,采用 @Autowired 注解注入属性值:
1 2 3 4 5 6 7 8 public class MessageServiceImpl implements MessageService { @Autowired private UserService userService; public String getMessage () { return userService.getMessage(); } }
1 <bean id ="messageService" class ="com.javadoop.example.MessageServiceImpl" />
以上这种属于混用了 xml 和 注解 两种方式的配置方式,Spring 会处理这种情况。
好了,读者要知道这么回事就可以了,继续向前。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 @Override protected Object createBean (String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException { if (logger.isDebugEnabled()) { logger.debug("Creating instance of bean '" + beanName + "'" ); } RootBeanDefinition mbdToUse = mbd; Class<?> resolvedClass = resolveBeanClass(mbd, beanName); if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null ) { mbdToUse = new RootBeanDefinition (mbd); mbdToUse.setBeanClass(resolvedClass); } try { mbdToUse.prepareMethodOverrides(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException (mbdToUse.getResourceDescription(), beanName, "Validation of method overrides failed" , ex); } try { Object bean = resolveBeforeInstantiation(beanName, mbdToUse); if (bean != null ) { return bean; } } catch (Throwable ex) { throw new BeanCreationException (mbdToUse.getResourceDescription(), beanName, "BeanPostProcessor before instantiation of bean failed" , ex); } Object beanInstance = doCreateBean(beanName, mbdToUse, args); if (logger.isDebugEnabled()) { logger.debug("Finished creating instance of bean '" + beanName + "'" ); } return beanInstance; }
创建 Bean 我们继续往里看 doCreateBean 这个方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 protected Object doCreateBean (final String beanName, final RootBeanDefinition mbd, final Object[] args) throws BeanCreationException { BeanWrapper instanceWrapper = null ; if (mbd.isSingleton()) { instanceWrapper = this .factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null ) { instanceWrapper = createBeanInstance(beanName, mbd, args); } final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null ); Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null ); mbd.resolvedTargetType = beanType; synchronized (mbd.postProcessingLock) { if (!mbd.postProcessed) { try { applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); } catch (Throwable ex) { throw new BeanCreationException (mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed" , ex); } mbd.postProcessed = true ; } } boolean earlySingletonExposure = (mbd.isSingleton() && this .allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { if (logger.isDebugEnabled()) { logger.debug("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references" ); } addSingletonFactory(beanName, new ObjectFactory <Object>() { @Override public Object getObject () throws BeansException { return getEarlyBeanReference(beanName, mbd, bean); } }); } Object exposedObject = bean; try { populateBean(beanName, mbd, instanceWrapper); if (exposedObject != null ) { exposedObject = initializeBean(beanName, exposedObject, mbd); } } catch (Throwable ex) { if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) { throw (BeanCreationException) ex; } else { throw new BeanCreationException ( mbd.getResourceDescription(), beanName, "Initialization of bean failed" , ex); } } if (earlySingletonExposure) { Object earlySingletonReference = getSingleton(beanName, false ); if (earlySingletonReference != null ) { if (exposedObject == bean) { exposedObject = earlySingletonReference; } else if (!this .allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) { String[] dependentBeans = getDependentBeans(beanName); Set<String> actualDependentBeans = new LinkedHashSet <String>(dependentBeans.length); for (String dependentBean : dependentBeans) { if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) { actualDependentBeans.add(dependentBean); } } if (!actualDependentBeans.isEmpty()) { throw new BeanCurrentlyInCreationException (beanName, "Bean with name '" + beanName + "' has been injected into other beans [" + StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + "] in its raw version as part of a circular reference, but has eventually been " + "wrapped. This means that said other beans do not use the final version of the " + "bean. This is often the result of over-eager type matching - consider using " + "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example." ); } } } } try { registerDisposableBeanIfNecessary(beanName, bean, mbd); } catch (BeanDefinitionValidationException ex) { throw new BeanCreationException ( mbd.getResourceDescription(), beanName, "Invalid destruction signature" , ex); } return exposedObject; }
到这里,我们已经分析完了 doCreateBean 方法,总的来说,我们已经说完了整个初始化流程。
接下来我们挑 doCreateBean 中的三个细节出来说说。一个是创建 Bean 实例的 createBeanInstance 方法,一个是依赖注入的 populateBean 方法,还有就是回调方法 initializeBean。
注意了,接下来的这三个方法要认真说那也是极其复杂的,很多地方我就点到为止了,感兴趣的读者可以自己往里看,最好就是碰到不懂的,自己写代码去调试它。
创建 Bean 实例 我们先看看 createBeanInstance 方法。需要说明的是,这个方法如果每个分支都分析下去,必然也是极其复杂冗长的,我们挑重点说。此方法的目的就是实例化我们指定的类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 protected BeanWrapper createBeanInstance (String beanName, RootBeanDefinition mbd, Object[] args) { Class<?> beanClass = resolveBeanClass(mbd, beanName); if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) { throw new BeanCreationException (mbd.getResourceDescription(), beanName, "Bean class isn't public, and non-public access not allowed: " + beanClass.getName()); } if (mbd.getFactoryMethodName() != null ) { return instantiateUsingFactoryMethod(beanName, mbd, args); } boolean resolved = false ; boolean autowireNecessary = false ; if (args == null ) { synchronized (mbd.constructorArgumentLock) { if (mbd.resolvedConstructorOrFactoryMethod != null ) { resolved = true ; autowireNecessary = mbd.constructorArgumentsResolved; } } } if (resolved) { if (autowireNecessary) { return autowireConstructor(beanName, mbd, null , null ); } else { return instantiateBean(beanName, mbd); } } Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); if (ctors != null || mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { return autowireConstructor(beanName, mbd, ctors, args); } return instantiateBean(beanName, mbd); }
挑个简单的无参构造函数构造实例来看看:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 protected BeanWrapper instantiateBean (final String beanName, final RootBeanDefinition mbd) { try { Object beanInstance; final BeanFactory parent = this ; if (System.getSecurityManager() != null ) { beanInstance = AccessController.doPrivileged(new PrivilegedAction <Object>() { @Override public Object run () { return getInstantiationStrategy().instantiate(mbd, beanName, parent); } }, getAccessControlContext()); } else { beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent); } BeanWrapper bw = new BeanWrapperImpl (beanInstance); initBeanWrapper(bw); return bw; } catch (Throwable ex) { throw new BeanCreationException ( mbd.getResourceDescription(), beanName, "Instantiation of bean failed" , ex); } }
我们可以看到,关键的地方在于:
1 beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
这里会进行实际的实例化过程,我们进去看看:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 @Override public Object instantiate (RootBeanDefinition bd, String beanName, BeanFactory owner) { if (bd.getMethodOverrides().isEmpty()) { Constructor<?> constructorToUse; synchronized (bd.constructorArgumentLock) { constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod; if (constructorToUse == null ) { final Class<?> clazz = bd.getBeanClass(); if (clazz.isInterface()) { throw new BeanInstantiationException (clazz, "Specified class is an interface" ); } try { if (System.getSecurityManager() != null ) { constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction <Constructor<?>>() { @Override public Constructor<?> run() throws Exception { return clazz.getDeclaredConstructor((Class[]) null ); } }); } else { constructorToUse = clazz.getDeclaredConstructor((Class[]) null ); } bd.resolvedConstructorOrFactoryMethod = constructorToUse; } catch (Throwable ex) { throw new BeanInstantiationException (clazz, "No default constructor found" , ex); } } } return BeanUtils.instantiateClass(constructorToUse); } else { return instantiateWithMethodInjection(bd, beanName, owner); } }
到这里,我们就算实例化完成了。我们开始说怎么进行属性注入。
bean 属性注入 看完了 createBeanInstance(…) 方法,我们来看看 populateBean(…) 方法,该方法负责进行属性设值,处理依赖。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 protected void populateBean (String beanName, RootBeanDefinition mbd, BeanWrapper bw) { PropertyValues pvs = mbd.getPropertyValues(); if (bw == null ) { if (!pvs.isEmpty()) { throw new BeanCreationException ( mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance" ); } else { return ; } } boolean continueWithPropertyPopulation = true ; if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { continueWithPropertyPopulation = false ; break ; } } } } if (!continueWithPropertyPopulation) { return ; } if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { MutablePropertyValues newPvs = new MutablePropertyValues (pvs); if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) { autowireByName(beanName, mbd, bw, newPvs); } if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { autowireByType(beanName, mbd, bw, newPvs); } pvs = newPvs; } boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors(); boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE); if (hasInstAwareBpps || needsDepCheck) { PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); if (hasInstAwareBpps) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); if (pvs == null ) { return ; } } } } if (needsDepCheck) { checkDependencies(beanName, mbd, filteredPds, pvs); } } applyPropertyValues(beanName, mbd, bw, pvs); }
initializeBean 属性注入完成后,这一步其实就是处理各种回调了,这块代码比较简单。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 protected Object initializeBean (final String beanName, final Object bean, RootBeanDefinition mbd) { if (System.getSecurityManager() != null ) { AccessController.doPrivileged(new PrivilegedAction <Object>() { @Override public Object run () { invokeAwareMethods(beanName, bean); return null ; } }, getAccessControlContext()); } else { invokeAwareMethods(beanName, bean); } Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try { invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) { throw new BeanCreationException ( (mbd != null ? mbd.getResourceDescription() : null ), beanName, "Invocation of init method failed" , ex); } if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }
大家发现没有,BeanPostProcessor 的两个回调都发生在这边,只不过中间处理了 init-method,是不是和读者原来的认知有点不一样了?
附录 id 和 name 每个 Bean 在 Spring 容器中都有一个唯一的名字(beanName)和 0 个或多个别名(aliases)。
我们从 Spring 容器中获取 Bean 的时候,可以根据 beanName,也可以通过别名。
1 beanFactory.getBean("beanName or alias" );
在配置的过程中,我们可以配置 id 和 name,看几个例子就知道是怎么回事了。
1 <bean id ="messageService" name ="m1, m2, m3" class ="com.javadoop.example.MessageServiceImpl" >
以上配置的结果就是:beanName 为 messageService,别名有 3 个,分别为 m1、m2、m3。
1 <bean name ="m1, m2, m3" class ="com.javadoop.example.MessageServiceImpl" />
以上配置的结果就是:beanName 为 m1,别名有 2 个,分别为 m2、m3。
1 <bean class ="com.javadoop.example.MessageServiceImpl" >
1 <bean class ="com.javadoop.example.MessageServiceImpl" >
beanName 为:com.javadoop.example.MessageServiceImpl#0,别名 1 个,为: com.javadoop.example.MessageServiceImpl
1 <bean id ="messageService" class ="com.javadoop.example.MessageServiceImpl" >
以上配置的结果就是:beanName 为 messageService,没有别名。
配置是否允许 Bean 覆盖、是否允许循环依赖 我们说过,默认情况下,allowBeanDefinitionOverriding 属性为 null。如果在同一配置文件中 Bean id 或 name 重复了,会抛错,但是如果不是同一配置文件中,会发生覆盖。
可是有些时候我们希望在系统启动的过程中就严格杜绝发生 Bean 覆盖,因为万一出现这种情况,会增加我们排查问题的成本。
循环依赖说的是 A 依赖 B,而 B 又依赖 A。或者是 A 依赖 B,B 依赖 C,而 C 却依赖 A。默认 allowCircularReferences 也是 null。
它们两个属性是一起出现的,必然可以在同一个地方一起进行配置。
添加这两个属性的作者 Juergen Hoeller 在这个 jira 的讨论中说明了怎么配置这两个属性。
1 2 3 4 5 6 7 8 9 public class NoBeanOverridingContextLoader extends ContextLoader { @Override protected void customizeContext (ServletContext servletContext, ConfigurableWebApplicationContext applicationContext) { super .customizeContext(servletContext, applicationContext); AbstractRefreshableApplicationContext arac = (AbstractRefreshableApplicationContext) applicationContext; arac.setAllowBeanDefinitionOverriding(false ); } }
1 2 3 4 5 6 7 public class MyContextLoaderListener extends org .springframework.web.context.ContextLoaderListener { @Override protected ContextLoader createContextLoader () { return new NoBeanOverridingContextLoader (); } }
1 2 3 <listener > <listener-class > com.javadoop.MyContextLoaderListener</listener-class > </listener >
如果以上方式不能满足你的需求,请参考这个链接:解决spring中不同配置文件中存在name或者id相同的bean可能引起的问题
profile 我们可以把不同环境的配置分别配置到单独的文件中,举个例子:
1 2 3 4 5 6 7 8 9 10 11 <beans profile ="development" xmlns ="http://www.springframework.org/schema/beans" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns:jdbc ="http://www.springframework.org/schema/jdbc" xsi:schemaLocation ="..." > <jdbc:embedded-database id ="dataSource" > <jdbc:script location ="classpath:com/bank/config/sql/schema.sql" /> <jdbc:script location ="classpath:com/bank/config/sql/test-data.sql" /> </jdbc:embedded-database > </beans >
1 2 3 4 5 6 7 8 <beans profile ="production" xmlns ="http://www.springframework.org/schema/beans" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns:jee ="http://www.springframework.org/schema/jee" xsi:schemaLocation ="..." > <jee:jndi-lookup id ="dataSource" jndi-name ="java:comp/env/jdbc/datasource" /> </beans >
应该不必做过多解释了吧,看每个文件第一行的 profile=””。
当然,我们也可以在一个配置文件中使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns:jdbc ="http://www.springframework.org/schema/jdbc" xmlns:jee ="http://www.springframework.org/schema/jee" xsi:schemaLocation ="..." > <beans profile ="development" > <jdbc:embedded-database id ="dataSource" > <jdbc:script location ="classpath:com/bank/config/sql/schema.sql" /> <jdbc:script location ="classpath:com/bank/config/sql/test-data.sql" /> </jdbc:embedded-database > </beans > <beans profile ="production" > <jee:jndi-lookup id ="dataSource" jndi-name ="java:comp/env/jdbc/datasource" /> </beans > </beans >
理解起来也很简单吧。
接下来的问题是,怎么使用特定的 profile 呢?Spring 在启动的过程中,会去寻找 “spring.profiles.active” 的属性值,根据这个属性值来的。那怎么配置这个值呢?
Spring 会在这几个地方寻找 spring.profiles.active 的属性值:操作系统环境变量、JVM 系统变量、web.xml 中定义的参数、JNDI。
最简单的方式莫过于在程序启动的时候指定:
1 -Dspring.profiles.active="profile1,profile2"
profile 可以激活多个
当然,我们也可以通过代码的形式从 Environment 中设置 profile:
1 2 3 4 AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext ();ctx.getEnvironment().setActiveProfiles("development" ); ctx.register(SomeConfig.class, StandaloneDataConfig.class, JndiDataConfig.class); ctx.refresh();
如果是 SpringBoot 的话更简单,我们一般会创建 application.properties、application-dev.properties、application-prod.properties 等文件。
其中 application.properties 配置各个环境通用的配置,application-{profile}.properties 中配置特定环境的配置,然后在启动的时候指定 profile:
1 java -Dspring.profiles.active=prod -jar JavaDoop.jar
如果是单元测试中使用的话,在测试类中使用 @ActiveProfiles 指定,这里就不展开了。
工厂模式生成 Bean 请读者注意 factory-bean 和 FactoryBean 的区别。这节说的是前者,是说静态工厂或实例工厂,而后者是 Spring 中的特殊接口,代表一类特殊的 Bean。
设计模式里,工厂方法模式分静态工厂和实例工厂,我们分别看看 Spring 中怎么配置这两个,来个代码示例就什么都清楚了。
静态工厂:
1 <bean id ="clientService" class ="examples.ClientService" factory-method ="createInstance" />
1 2 3 4 5 6 7 public class ClientService { private static ClientService clientService = new ClientService (); private ClientService () {} public static ClientService createInstance () { return clientService; } }
实例工厂:
1 2 3 4 5 6 7 8 9 10 11 <bean id ="serviceLocator" class ="examples.DefaultServiceLocator" > </bean > <bean id ="clientService" factory-bean ="serviceLocator" factory-method ="createClientServiceInstance" /> <bean id ="accountService" factory-bean ="serviceLocator" factory-method ="createAccountServiceInstance" />
1 2 3 4 5 6 7 8 9 10 public class DefaultServiceLocator { private static ClientService clientService = new ClientServiceImpl (); private static AccountService accountService = new AccountServiceImpl (); public ClientService createClientServiceInstance () { return clientService; } public AccountService createAccountServiceInstance () { return accountService; } }
FactoryBean FactoryBean 适用于 Bean 的创建过程比较复杂的场景,比如数据库连接池的创建。
1 2 3 4 5 public interface FactoryBean <T> { T getObject () throws Exception; Class<T> getObjectType () ; boolean isSingleton () ; }
1 2 3 4 5 public class Person { private Car car; private void setCar (Car car) { this .car = car; } }
我们假设现在需要创建一个 Person 的 Bean,首先我们需要一个 Car 的实例,我们这里假设 Car 的实例创建很麻烦,那么我们可以把创建 Car 的复杂过程包装起来:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class MyCarFactoryBean implements FactoryBean <Car> { private String make; private int year; public void setMake (String m) { this .make = m; } public void setYear (int y) { this .year = y; } public Car getObject () { CarBuilder cb = CarBuilder.car(); if (year != 0 ) cb.setYear(this .year); if (StringUtils.hasText(this .make)) cb.setMake(this .make); return cb.factory(); } public Class<Car> getObjectType () { return Car.class; } public boolean isSingleton () { return false ; } }
我们看看装配的时候是怎么配置的:
1 2 3 4 5 6 7 <bean class = "com.javadoop.MyCarFactoryBean" id = "car" > <property name = "make" value ="Honda" /> <property name = "year" value ="1984" /> </bean > <bean class = "com.javadoop.Person" id = "josh" > <property name = "car" ref = "car" /> </bean >
看到不一样了吗?id 为 “car” 的 bean 其实指定的是一个 FactoryBean,不过配置的时候,我们直接让配置 Person 的 Bean 直接依赖于这个 FactoryBean 就可以了。中间的过程 Spring 已经封装好了。
说到这里,我们再来点干货。我们知道,现在还用 xml 配置 Bean 依赖的越来越少了,更多时候,我们可能会采用 java config 的方式来配置,这里有什么不一样呢?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @Configuration public class CarConfiguration { @Bean public MyCarFactoryBean carFactoryBean () { MyCarFactoryBean cfb = new MyCarFactoryBean (); cfb.setMake("Honda" ); cfb.setYear(1984 ); return cfb; } @Bean public Person aPerson () { Person person = new Person (); person.setCar(carFactoryBean().getObject()); return person; } }
这个时候,其实我们的思路也很简单,把 MyCarFactoryBean 看成是一个简单的 Bean 就可以了,不必理会什么 FactoryBean,它是不是 FactoryBean 和我们没关系。
初始化 Bean 的回调 有以下四种方案:
1 <bean id ="exampleInitBean" class ="examples.ExampleBean" init-method ="init" />
1 2 3 4 5 6 public class AnotherExampleBean implements InitializingBean { public void afterPropertiesSet () { } }
1 2 3 4 @Bean(initMethod = "init") public Foo foo () { return new Foo (); }
1 2 3 4 @PostConstruct public void init () {}
销毁 Bean 的回调 1 <bean id ="exampleInitBean" class ="examples.ExampleBean" destroy-method ="cleanup" />
1 2 3 4 5 6 public class AnotherExampleBean implements DisposableBean { public void destroy () { } }
1 2 3 4 @Bean(destroyMethod = "cleanup") public Bar bar () { return new Bar (); }
1 2 3 4 @PreDestroy public void cleanup () {}
ConversionService 最有用的场景:用来将前端传过来的参数和后端的 controller 方法上的参数进行绑定。
像前端传过来的字符串、整数要转换为后端的 String、Integer 很容易,但是如果 controller 方法需要的是一个枚举值,或者是 Date 这些非基础类型(含基础类型包装类)值的时候,我们就可以考虑采用 ConversionService 来进行转换。
1 2 3 4 5 6 7 8 <bean id ="conversionService" class ="org.springframework.context.support.ConversionServiceFactoryBean" > <property name ="converters" > <list > <bean class ="com.javadoop.learning.utils.StringToEnumConverterFactory" /> </list > </property > </bean >
ConversionService 接口很简单,所以要自定义一个 convert 的话也很简单。
下面再说一个实现这种转换很简单的方式,那就是实现 Converter 接口。
来看一个很简单的例子,这样比什么都管用。
1 2 3 4 5 6 7 8 9 10 11 public class StringToDateConverter implements Converter <String, Date> { @Override public Date convert (String source) { try { return DateUtils.parseDate(source, "yyyy-MM-dd" , "yyyy-MM-dd HH:mm:ss" , "yyyy-MM-dd HH:mm" , "HH:mm:ss" , "HH:mm" ); } catch (ParseException e) { return null ; } } }
只要注册这个 Bean 就可以了。这样,前端往后端传的时间描述字符串就很容易绑定成 Date 类型了,不需要其他任何操作。
Bean 继承 在初始化 Bean 的地方,我们说过了这个:
1 RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
这里涉及到的就是 <bean parent=”” /> 中的 parent 属性,我们来看看 Spring 中是用这个来干什么的。
首先,我们要明白,这里的继承和 Java 语法中的继承没有任何关系,不过思路是相通的。child bean 会继承 parent bean 的所有配置,也可以覆盖一些配置,当然也可以新增额外的配置。
Spring 中提供了继承自 AbstractBeanDefinition 的 ChildBeanDefinition 来表示 child bean。
看如下一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <bean id ="inheritedTestBean" abstract ="true" class ="org.springframework.beans.TestBean" > <property name ="name" value ="parent" /> <property name ="age" value ="1" /> </bean > <bean id ="inheritsWithDifferentClass" class ="org.springframework.beans.DerivedTestBean" parent ="inheritedTestBean" init-method ="initialize" > <property name ="name" value ="override" /> </bean >
parent bean 设置了 abstract=”true” 所以它不会被实例化,child bean 继承了 parent bean 的两个属性,但是对 name 属性进行了覆写。
child bean 会继承 scope、构造器参数值、属性值、init-method、destroy-method 等等。
当然,我不是说 parent bean 中的 abstract = true 在这里是必须的,只是说如果加上了以后 Spring 在实例化 singleton beans 的时候会忽略这个 bean。
比如下面这个极端 parent bean,它没有指定 class,所以毫无疑问,这个 bean 的作用就是用来充当模板用的 parent bean,此处就必须加上 abstract = true。
1 2 3 4 <bean id ="inheritedTestBeanWithoutClass" abstract ="true" > <property name ="name" value ="parent" /> <property name ="age" value ="1" /> </bean >
方法注入 一般来说,我们的应用中大多数的 Bean 都是 singleton 的。singleton 依赖 singleton,或者 prototype 依赖 prototype 都很好解决,直接设置属性依赖就可以了。
但是,如果是 singleton 依赖 prototype 呢?这个时候不能用属性依赖,因为如果用属性依赖的话,我们每次其实拿到的还是第一次初始化时候的 bean。
一种解决方案就是不要用属性依赖,每次获取依赖的 bean 的时候从 BeanFactory 中取。这个也是大家最常用的方式了吧。怎么取,我就不介绍了,大部分 Spring 项目大家都会定义那么个工具类的。
另一种解决方案就是这里要介绍的通过使用 Lookup method。
lookup-method 我们来看一下 Spring Reference 中提供的一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package fiona.apple;public abstract class CommandManager { public Object process (Object commandState) { Command command = createCommand(); command.setState(commandState); return command.execute(); } protected abstract Command createCommand () ; }
xml 配置 <lookup-method />:
1 2 3 4 5 6 7 8 9 <bean id ="myCommand" class ="fiona.apple.AsyncCommand" scope ="prototype" > </bean > <bean id ="commandManager" class ="fiona.apple.CommandManager" > <lookup-method name ="createCommand" bean ="myCommand" /> </bean >
Spring 采用 CGLIB 生成字节码的方式来生成一个子类。我们定义的类不能定义为 final class,抽象方法上也不能加 final。
lookup-method 上的配置也可以采用注解来完成,这样就可以不用配置了,其他不变:
1 2 3 4 5 6 7 8 9 10 11 public abstract class CommandManager { public Object process (Object commandState) { MyCommand command = createCommand(); command.setState(commandState); return command.execute(); } @Lookup("myCommand") protected abstract Command createCommand () ; }
注意,既然用了注解,要配置注解扫描:<context:component-scan base-package=”com.javadoop” />
甚至,我们可以像下面这样:
1 2 3 4 5 6 7 8 9 10 11 public abstract class CommandManager { public Object process (Object commandState) { MyCommand command = createCommand(); command.setState(commandState); return command.execute(); } @Lookup protected abstract MyCommand createCommand () ; }
上面的返回值用了 MyCommand,当然,如果 Command 只有一个实现类,那返回值也可以写 Command。
replaced-method 记住它的功能,就是替换掉 bean 中的一些方法。
1 2 3 4 5 6 7 8 public class MyValueCalculator { public String computeValue (String input) { } }
方法覆写,注意要实现 MethodReplacer 接口:
1 2 3 4 5 6 7 8 9 public class ReplacementComputeValue implements org .springframework.beans.factory.support.MethodReplacer { public Object reimplement (Object o, Method m, Object[] args) throws Throwable { String input = (String) args[0 ]; ... return ...; } }
配置也很简单:
1 2 3 4 5 6 7 8 <bean id ="myValueCalculator" class ="x.y.z.MyValueCalculator" > <replaced-method name ="computeValue" replacer ="replacementComputeValue" > <arg-type > String</arg-type > </replaced-method > </bean > <bean id ="replacementComputeValue" class ="a.b.c.ReplacementComputeValue" />
arg-type 明显不是必须的,除非存在方法重载,这样必须通过参数类型列表来判断这里要覆盖哪个方法。
BeanPostProcessor 应该说 BeanPostProcessor 概念在 Spring 中也是比较重要的。我们看下接口定义:
1 2 3 4 5 6 public interface BeanPostProcessor { Object postProcessBeforeInitialization (Object bean, String beanName) throws BeansException; Object postProcessAfterInitialization (Object bean, String beanName) throws BeansException; }
看这个接口中的两个方法名字我们大体上可以猜测 bean 在初始化之前会执行 postProcessBeforeInitialization 这个方法,初始化完成之后会执行 postProcessAfterInitialization 这个方法。但是,这么理解是非常片面的。
首先,我们要明白,除了我们自己定义的 BeanPostProcessor 实现外,Spring 容器在启动时自动给我们也加了几个。如在获取 BeanFactory 的 obtainFactory() 方法结束后的 prepareBeanFactory(factory),大家仔细看会发现,Spring 往容器中添加了这两个 BeanPostProcessor:ApplicationContextAwareProcessor、ApplicationListenerDetector。
我们回到这个接口本身,读者请看第一个方法,这个方法接受的第一个参数是 bean 实例,第二个参数是 bean 的名字,重点在返回值将会作为新的 bean 实例,所以,没事的话这里不能随便返回个 null。
那意味着什么呢?我们很容易想到的就是,我们这里可以对一些我们想要修饰的 bean 实例做一些事情。但是对于 Spring 框架来说,它会决定是不是要在这个方法中返回 bean 实例的代理,这样就有更大的想象空间了。
最后,我们说说如果我们自己定义一个 bean 实现 BeanPostProcessor 的话,它的执行时机是什么时候?
如果仔细看了代码分析的话,其实很容易知道了,在 bean 实例化完成、属性注入完成之后,会执行回调方法,具体请参见类 AbstractAutowireCapableBeanFactory#initBean 方法。
首先会回调几个实现了 Aware 接口的 bean,然后就开始回调 BeanPostProcessor 的 postProcessBeforeInitialization 方法,之后是回调 init-method,然后再回调 BeanPostProcessor 的 postProcessAfterInitialization 方法。