spring源码分析(一)IoC、DI
创建日期:2016.08.06
修改日期:2016.08.07 - 2016.08.12
交流QQ:992591601
参考书籍:《spring源码深度解析》、《spring技术内幕》
参考文章:http://www.cnblogs.com/xing901022/p/4178963.html
http://www.myexception.cn/program/1031276.html
http://blog.csdn.net/qian_348840260/article/details/7994936
一、搭建工程,运行简单示例:
- @Test
- public void testSimpleLoad() {
- BeanFactory bf = new XmlBeanFactory(new ClassPathResource ("beans.xml"));
- Person bean = (Person) bf.getBean("person");
- bean.info();
- }
其余代码我就不贴了,很基本。要说明一点,要看spring源码的话,需要在导入的spring jar包附上额外的源码包,eclipse可以配置:
二、这个工程的test程序只有短短几行,但背后的spring代码却是繁多复杂的。
BeanFactory bf = new XmlBeanFactory(new ClassPathResource ("beans.xml"));
Person bean = (Person) bf.getBean("person");
这两句的逻辑看起来很简单,首先依据xml文件创建工厂类,再通过工厂类从容器获取bean。在这个过程中用ClassPathResource类来对配置文件作一个包装,然后作为XmlBeanFactory构造函数的参数。
BeanFactory是一个接口。
先来看ClassPathResource类。经过代码阅读,可以总结UML图:
可以清晰看得出来,spring的设计者在这里应用了一个著名设计模式:策略模式。简单些讲,就是面向接口编程的一种思路。在这里UrlResource和ClassPathResource都实现了Resource接口,是Resource接口的两种实现策略。
我们首先看Resource接口,这是最基础的定义:
- public interface Resource extends InputStreamSource {
- boolean exists();
- boolean isReadable();
- boolean isOpen();
- URL getURL() throws IOException;
- URI getURI() throws IOException;
- File getFile() throws IOException;
- long contentLength() throws IOException;
- long lastModified() throws IOException;
- Resource createRelative(String relativePath) throws IOException;
- String getFilename();
- String getDescription();
- }
该接口定义了一些很基本的方法。都是一些很必要的get操作。具体实现自然要交给两个策略来实现:UrlResource和ClassPathResource。另外,值得一提的是该接口还继承了一个接口InputStreamSource。该接口只定义了一个方法:
InputStream getInputStream() throws IOException; 是用来获取java I/O的。
抽象类AbstractResource是接口与实现策略之间的中间层。实现了Resource接口的所有方法。在此基础上,策略类继承该抽象类之后,就只需提供自己特有的方法即可了。然而很多方法例如getURL都要在策略类里重写的,因为url这种数据还是要具体实例化时才能得到。
具体实现细节不多说,总结一下,就是spring的资源文件通过Resource接口的实现类来包装。而这些实现类与Resource接口的关系是一种策略模式。
接下来看XmlBeanFactory类的代码:
- public class XmlBeanFactory extends DefaultListableBeanFactory {
- private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
- /**
- * Create a new XmlBeanFactory with the given resource,
- * which must be parsable using DOM.
- * @param resource XML resource to load bean definitions from
- * @throws BeansException in case of loading or parsing errors
- */
- public XmlBeanFactory(Resource resource) throws BeansException {
- this(resource, null);
- }
- /**
- * Create a new XmlBeanFactory with the given input stream,
- * which must be parsable using DOM.
- * @param resource XML resource to load bean definitions from
- * @param parentBeanFactory parent bean factory
- * @throws BeansException in case of loading or parsing errors
- */
- public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
- super(parentBeanFactory);
- this.reader.loadBeanDefinitions(resource);
- }
- }
XmlBeanFactory将Resource作为构造函数参数。这里XmlBeanDefinitionReader是关键,用来根据Resource来loadBeanDefinitions。这是XmlBeanFactory对基类DefaultListableBeanFactory的添加。
EncodeResource是对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();
- }
- }
- }
该方法作用是将XML文件转化为BeanDefinitions。
这段代码意思是:
1,获取线程局部变量resourcesCurrentlyBeingLoaded, final ThreadLocal<Set<EncodedResource>>类型。
将当前要加载的Source,放入final ThreadLocal<Set<EncodedResource>>,若无法放入则抛出异常。
2,核心,真正的去加载Resource:
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();
}
3,将加载过的Resource从resourcesCurrentlyBeingLoaded删除。
这里面1和3涉及多线程操作,这里面了解下java的ThreadLocal:ThreadLocal是指线程类的局部变量,他可以保证每一个线程都保有一份自己的局部变量的副本,线程之间不会对别的线程的ThreadLocal产生影响。
从代码上看,1和3的意义就是用ThreadLocal标注当前线程正在加载的Resource。
2是核心部分,调用doLoadBeanDefinitions(InputSource inputSource, Resource resource)方法
- protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
- throws BeanDefinitionStoreException {
- try {
- int validationMode = getValidationModeForResource(resource);
- Document doc = this.documentLoader.loadDocument(
- inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
- return registerBeanDefinitions(doc, resource);
- }
- catch (BeanDefinitionStoreException ex) {
- throw ex;
- }
- catch (SAXParseException ex) {
- throw new XmlBeanDefinitionStoreException(resource.getDescription(),
- "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
- }
- catch (SAXException ex) {
- throw new XmlBeanDefinitionStoreException(resource.getDescription(),
- "XML document from " + resource + " is invalid", ex);
- }
- catch (ParserConfigurationException ex) {
- throw new BeanDefinitionStoreException(resource.getDescription(),
- "Parser configuration exception parsing XML from " + resource, ex);
- }
- catch (IOException ex) {
- throw new BeanDefinitionStoreException(resource.getDescription(),
- "IOException parsing XML document from " + resource, ex);
- }
- catch (Throwable ex) {
- throw new BeanDefinitionStoreException(resource.getDescription(),
- "Unexpected exception parsing XML document from " + resource, ex);
- }
- }
关键是这三句:
int validationMode = getValidationModeForResource(resource);
Document doc = this.documentLoader.loadDocument(
inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
return registerBeanDefinitions(doc, resource);
继续看loadDocument方法代码:
- public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
- ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
- DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
- if (logger.isDebugEnabled()) {
- logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");
- }
- DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
- return builder.parse(inputSource);
- }
关于参数,entityResolver,解释起来有些麻烦,直接引用《spring源码深度解析》一书的文字吧:
int validationMode = getValidationModeForResource(resource); 这句是获取对应资源的验证方式。两种验证模式:DTD、XSD
这里DocumentBuilder的创建方式体现了工厂模式。具体创建是靠DocumentBuilderFactory factory作为参数。而factory的创建是方法protected DocumentBuilderFactory createDocumentBuilderFactory(int validationMode, boolean namespaceAware)
DocumentBuilderFactory和DocumentBuilder都是抽象类,真正实例化的是对抽象类的实现类。
不管怎么样,它return builder.parse(inputSource) return的是一个Document类。
Document接口注释:
* The <code>Document</code> interface represents the entire HTML or XML
* document. Conceptually, it is the root of the document tree, and provides
* the primary access to the document's data.
而Document接口又是继承了Node接口。
loadDocument方法就是将文件转化为Document类的过程。
继续看代码:
- public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
- // Read document based on new BeanDefinitionDocumentReader SPI.
- BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
- int countBefore = getRegistry().getBeanDefinitionCount();
- documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
- return getRegistry().getBeanDefinitionCount() - countBefore;
- }
- public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
- this.readerContext = readerContext;
- logger.debug("Loading bean definitions");
- Element root = doc.getDocumentElement();
- BeanDefinitionParserDelegate delegate = createHelper(readerContext, root);
- preProcessXml(root);
- parseBeanDefinitions(root, delegate);
- postProcessXml(root);
- }
- protected BeanDefinitionParserDelegate createHelper(XmlReaderContext readerContext, Element root) {
- BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
- delegate.initDefaults(root);
- return delegate;
- }
Element root = doc.getDocumentElement();获取根节点Element。
/**
* The <code>Element</code> interface represents an element in an HTML or XML
* document. Elements may have attributes associated with them; since the
* <code>Element</code> interface inherits from <code>Node</code>, the
* generic <code>Node</code> interface attribute <code>attributes</code> may
* be used to retrieve the set of all attributes for an element. There are
* methods on the <code>Element</code> interface to retrieve either an
* <code>Attr</code> object by name or an attribute value by name. In XML,
* where an attribute value may contain entity references, an
* <code>Attr</code> object should be retrieved to examine the possibly
* fairly complex sub-tree representing the attribute value. On the other
* hand, in HTML, where all attributes have simple string values, methods to
* directly access an attribute value can safely be used as a convenience.
* <p ><b>Note:</b> In DOM Level 2, the method <code>normalize</code> is
* inherited from the <code>Node</code> interface where it was moved.
* <p>See also the <a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>Document Object Model (DOM) Level 3 Core Specification</a>.
*/
public interface Element extends Node{……}
而这里的BeanDefinitionParserDelegate delegate是用来做转换工作。
spring源码的阅读工作就是一层套一层……然而并不难搞懂
理解下面的代码必须要提及spring XML配置里有两种bean的声明,一种是默认的<bean id = "test" class = "test.TestBean"/>另一种就是自定义的:<tx:annotation-driven/>:
- /**
- * Parse the elements at the root level in the document:
- * "import", "alias", "bean".
- * @param root the DOM root element of the document
- */
- protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
- //如果是默认方式声明bean
- 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);
- }
- }
- }
- }
- //自定义方式声明bean
- else {
- delegate.parseCustomElement(root);
- }
- }
这里是从根节点,开始转换。
继续看核心操作parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)方法:
- 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);
- }
- }
看代码感觉这是在根据节点名称类型选择注册操作,继续看void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)方法:
- /**
- * Process the given bean element, parsing the bean definition
- * and registering it with the registry.
- */
- 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));
- }
- }
这里BeanDefinitionHolder也是采用了装饰者模式。包含了BeanDefinition,添加了:
private final String beanName;
private final String[] aliases;
两个私有final变量。
另外注意BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());这句。
- 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 aliase : aliases) {
- registry.registerAlias(beanName, aliase);
- }
- }
- }
BeanDefinitionRegistry是XMLBeanFactory的基类之一。设置断点跟踪,我们可以发现,进入这个方法,传进来的类实例正是XmlBeanFactory。接下来调用的是XmlBeanFactory类的方法,registerBeanDefinition。方法内部调用的这里是真正的注册的实现:将BeanDefinition添加的,Spring的BeanFactory容器里,一个Map数据结构:
/** Map of bean definition objects, keyed by bean name */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();
- 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.getResourceDescription(), beanName,
- "Validation of bean definition failed", ex);
- }
- }
- synchronized (this.beanDefinitionMap) {
- Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);
- if (oldBeanDefinition != null) {
- if (!this.allowBeanDefinitionOverriding) {
- throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
- "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
- "': There is already [" + oldBeanDefinition + "] bound.");
- }
- else {
- if (this.logger.isInfoEnabled()) {
- this.logger.info("Overriding bean definition for bean '" + beanName +
- "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
- }
- }
- }
- else {
- this.beanDefinitionNames.add(beanName);
- this.frozenBeanDefinitionNames = null;
- }
- this.beanDefinitionMap.put(beanName, beanDefinition);
- resetBeanDefinition(beanName);
- }
- }
以上所述就是BeanFactory bf = new XmlBeanFactory(new ClassPathResource ("beans.xml"));这句代码背后的故事。
首先,ClassPathResource类封装了资源文件,作为构造函数参数来创建XmlBeanFactory。经过一系列复杂转换将XML文件转换为spring需要的数据结构~ BeanDefinition
对XML的解析和BeanDefinition就介绍到这,介绍的并不够绝对细致,主要是理解大意,另外也是spring源码确实比较繁杂。并且以后有了新的心得还会在这篇文章做修改补充。
接下来这句:Person bean = (Person) bf.getBean("person");
代码的字面意思就是从spring容器里,获取person bean的实例对象。
这里要提到BeanFactory和ApplicationContext的区别:BeanFactory是采取延迟加载,只有当getBean的时候才会去加载、实例化这个对象。ApplicationContext则正相反,它是一次性加载所有bean。
getBean的最终实现是 AbstractBeanFactory的 doGetBean方法
- @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;
- // Eagerly check singleton cache for manually registered singletons.
- Object sharedInstance = getSingleton(beanName);
- if (sharedInstance != null && args == null) {
- if (logger.isDebugEnabled()) {
- if (isSingletonCurrentlyInCreation(beanName)) {
- logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
- "' that is not fully initialized yet - a consequence of a circular reference");
- }
- else {
- logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
- }
- }
- bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
- }
- else {
- // Fail if we're already creating this bean instance:
- // We're assumably within a circular reference.
- if (isPrototypeCurrentlyInCreation(beanName)) {
- throw new BeanCurrentlyInCreationException(beanName);
- }
- // Check if bean definition exists in this factory.
- BeanFactory parentBeanFactory = getParentBeanFactory();
- if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
- // Not found -> check parent.
- String nameToLookup = originalBeanName(name);
- if (args != null) {
- // Delegation to parent with explicit args.
- return (T) parentBeanFactory.getBean(nameToLookup, args);
- }
- else {
- // No args -> delegate to standard getBean method.
- return parentBeanFactory.getBean(nameToLookup, requiredType);
- }
- }
- if (!typeCheckOnly) {
- markBeanAsCreated(beanName);
- }
- final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
- checkMergedBeanDefinition(mbd, beanName, args);
- // Guarantee initialization of beans that the current bean depends on.
- String[] dependsOn = mbd.getDependsOn();
- if (dependsOn != null) {
- for (String dependsOnBean : dependsOn) {
- getBean(dependsOnBean);
- registerDependentBean(dependsOnBean, beanName);
- }
- }
- // Create bean instance.
- if (mbd.isSingleton()) {
- sharedInstance = getSingleton(beanName, new ObjectFactory() {
- public Object getObject() throws BeansException {
- try {
- return createBean(beanName, mbd, args);
- }
- catch (BeansException ex) {
- // Explicitly remove instance from singleton cache: It might have been put there
- // eagerly by the creation process, to allow for circular reference resolution.
- // Also remove any beans that received a temporary reference to the bean.
- destroySingleton(beanName);
- throw ex;
- }
- }
- });
- bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
- }
- else if (mbd.isPrototype()) {
- // It's a prototype -> create a new instance.
- 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 '" + scopeName + "'");
- }
- try {
- Object scopedInstance = scope.get(beanName, new ObjectFactory() {
- 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);
- }
- }
- }
- // Check if required type matches the type of the actual bean instance.
- if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
- throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
- }
- return (T) bean;
- }
看这个代码英文注释就明白了
1、Eagerly check singleton cache for manually registered singletons.
2、Check if bean definition exists in this factory.Not found -> check parent.(当前BeanFactory不存在,则通过递归,向上寻找。parentBeanFactory是XmlBeanFactory的成员变量。)
3、Guarantee initialization of beans that the current bean depends on.(生成依赖bean)
4、Create bean instance.(创建bean)(创建bean的过程会查看是singleton还是prototype,如果是singleton是单例模式,只会被创建一次,prototype则每次getBean相当于new一次。代码中首先通过Object sharedInstance = getSingleton(beanName);根据bean名称获取单例对象,若为空再创建);
- @Override
- protected Object createBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
- throws BeanCreationException {
- if (logger.isDebugEnabled()) {
- logger.debug("Creating instance of bean '" + beanName + "'");
- }
- // Make sure bean class is actually resolved at this point.
- resolveBeanClass(mbd, beanName);
- // Prepare method overrides.
- try {
- mbd.prepareMethodOverrides();
- }
- catch (BeanDefinitionValidationException ex) {
- throw new BeanDefinitionStoreException(mbd.getResourceDescription(),
- beanName, "Validation of method overrides failed", ex);
- }
- try {
- // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
- Object bean = resolveBeforeInstantiation(beanName, mbd);
- if (bean != null) {
- return bean;
- }
- }
- catch (Throwable ex) {
- throw new BeanCreationException(mbd.getResourceDescription(), beanName,
- "BeanPostProcessor before instantiation of bean failed", ex);
- }
- Object beanInstance = doCreateBean(beanName, mbd, args);
- if (logger.isDebugEnabled()) {
- logger.debug("Finished creating instance of bean '" + beanName + "'");
- }
- return beanInstance;
- }
通过注解理解其意义:
// Make sure bean class is actually resolved at this point.(确保bean类此时已被分解)
resolveBeanClass(mbd, beanName);
// Prepare method overrides.(准备实现接口的方法)
mbd.prepareMethodOverrides();
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.(如果可能的话,返回一个代理而不是实例的对象)
Object bean = resolveBeforeInstantiation(beanName, mbd);
最后这里才是真正核心的实例化bean的方法:
Object beanInstance = doCreateBean(beanName, mbd, args);
doCreateBean中有两个重要的方法,一个是createBeanInstance,用于实例化bean。
另一个是这句populateBean(beanName, mbd, instanceWrapper);这个方法用于依赖关系的处理过程。
- /**
- * Actually create the specified bean. Pre-creation processing has already happened
- * at this point, e.g. checking <code>postProcessBeforeInstantiation</code> callbacks.
- * <p>Differentiates between default bean instantiation, use of a
- * factory method, and autowiring a constructor.
- * @param beanName the name of the bean
- * @param mbd the merged bean definition for the bean
- * @param args arguments to use if creating a prototype using explicit arguments to a
- * static factory method. This parameter must be <code>null</code> except in this case.
- * @return a new instance of the bean
- * @throws BeanCreationException if the bean could not be created
- * @see #instantiateBean
- * @see #instantiateUsingFactoryMethod
- * @see #autowireConstructor
- */
- protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
- // Instantiate the bean.
- 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);
- // Allow post-processors to modify the merged bean definition.
- synchronized (mbd.postProcessingLock) {
- if (!mbd.postProcessed) {
- applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
- mbd.postProcessed = true;
- }
- }
- // Eagerly cache singletons to be able to resolve circular references
- // even when triggered by lifecycle interfaces like BeanFactoryAware.
- 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() {
- public Object getObject() throws BeansException {
- return getEarlyBeanReference(beanName, mbd, bean);
- }
- });
- }
- // Initialize the bean instance.
- 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.");
- }
- }
- }
- }
- // Register bean as disposable.
- try {
- registerDisposableBeanIfNecessary(beanName, bean, mbd);
- }
- catch (BeanDefinitionValidationException ex) {
- throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
- }
- return exposedObject;
- }
这里面createBeanInstance方法用于实例化bean。下面可以看到实例化的bean的方式不止一种,有工厂方法方式,也有构造方法方式。主要根据BeanDefinition中的信息。
- /**
- * Create a new instance for the specified bean, using an appropriate instantiation strategy:
- * factory method, constructor autowiring, or simple instantiation.
- * @param beanName the name of the bean
- * @param mbd the bean definition for the bean
- * @param args arguments to use if creating a prototype using explicit arguments to a
- * static factory method. It is invalid to use a non-null args value in any other case.
- * @return BeanWrapper for the new instance
- * @see #instantiateUsingFactoryMethod
- * @see #autowireConstructor
- * @see #instantiateBean
- */
- protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
- // Make sure bean class is actually resolved at this point.
- 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);
- }
- // Shortcut when re-creating the same bean...
- 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);
- }
- }
- // Need to determine the constructor...
- Constructor[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
- if (ctors != null ||
- mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
- mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
- return autowireConstructor(beanName, mbd, ctors, args);
- }
- // No special handling: simply use no-arg constructor.
- return instantiateBean(beanName, mbd);
- }
工厂方法模式:
- /**
- * Instantiate the bean using a named factory method. The method may be static, if the
- * bean definition parameter specifies a class, rather than a "factory-bean", or
- * an instance variable on a factory object itself configured using Dependency Injection.
- * <p>Implementation requires iterating over the static or instance methods with the
- * name specified in the RootBeanDefinition (the method may be overloaded) and trying
- * to match with the parameters. We don't have the types attached to constructor args,
- * so trial and error is the only way to go here. The explicitArgs array may contain
- * argument values passed in programmatically via the corresponding getBean method.
- * @param beanName the name of the bean
- * @param mbd the merged bean definition for the bean
- * @param explicitArgs argument values passed in programmatically via the getBean
- * method, or <code>null</code> if none (-> use constructor argument values from bean definition)
- * @return a BeanWrapper for the new instance
- */
- public BeanWrapper instantiateUsingFactoryMethod(final String beanName, final RootBeanDefinition mbd, final Object[] explicitArgs) {
- BeanWrapperImpl bw = new BeanWrapperImpl();
- this.beanFactory.initBeanWrapper(bw);
- Object factoryBean;
- Class factoryClass;
- boolean isStatic;
- String factoryBeanName = mbd.getFactoryBeanName();
- if (factoryBeanName != null) {
- if (factoryBeanName.equals(beanName)) {
- throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
- "factory-bean reference points back to the same bean definition");
- }
- factoryBean = this.beanFactory.getBean(factoryBeanName);
- if (factoryBean == null) {
- throw new BeanCreationException(mbd.getResourceDescription(), beanName,
- "factory-bean '" + factoryBeanName + "' returned null");
- }
- factoryClass = factoryBean.getClass();
- isStatic = false;
- }
- else {
- // It's a static factory method on the bean class.
- if (!mbd.hasBeanClass()) {
- throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
- "bean definition declares neither a bean class nor a factory-bean reference");
- }
- factoryBean = null;
- factoryClass = mbd.getBeanClass();
- isStatic = true;
- }
- Method factoryMethodToUse = null;
- ArgumentsHolder argsHolderToUse = null;
- Object[] argsToUse = null;
- if (explicitArgs != null) {
- argsToUse = explicitArgs;
- }
- else {
- Object[] argsToResolve = null;
- synchronized (mbd.constructorArgumentLock) {
- factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;
- if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {
- // Found a cached factory method...
- argsToUse = mbd.resolvedConstructorArguments;
- if (argsToUse == null) {
- argsToResolve = mbd.preparedConstructorArguments;
- }
- }
- }
- if (argsToResolve != null) {
- argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve);
- }
- }
- if (factoryMethodToUse == null || argsToUse == null) {
- // Need to determine the factory method...
- // Try all methods with this name to see if they match the given arguments.
- factoryClass = ClassUtils.getUserClass(factoryClass);
- Method[] rawCandidates;
- final Class factoryClazz = factoryClass;
- if (System.getSecurityManager() != null) {
- rawCandidates = AccessController.doPrivileged(new PrivilegedAction<Method[]>() {
- public Method[] run() {
- return (mbd.isNonPublicAccessAllowed() ?
- ReflectionUtils.getAllDeclaredMethods(factoryClazz) : factoryClazz.getMethods());
- }
- });
- }
- else {
- rawCandidates = (mbd.isNonPublicAccessAllowed() ?
- ReflectionUtils.getAllDeclaredMethods(factoryClazz) : factoryClazz.getMethods());
- }
- List<Method> candidateSet = new ArrayList<Method>();
- for (Method candidate : rawCandidates) {
- if (Modifier.isStatic(candidate.getModifiers()) == isStatic &&
- candidate.getName().equals(mbd.getFactoryMethodName()) &&
- mbd.isFactoryMethod(candidate)) {
- candidateSet.add(candidate);
- }
- }
- Method[] candidates = candidateSet.toArray(new Method[candidateSet.size()]);
- AutowireUtils.sortFactoryMethods(candidates);
- ConstructorArgumentValues resolvedValues = null;
- boolean autowiring = (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
- int minTypeDiffWeight = Integer.MAX_VALUE;
- Set<Method> ambiguousFactoryMethods = null;
- int minNrOfArgs;
- if (explicitArgs != null) {
- minNrOfArgs = explicitArgs.length;
- }
- else {
- // We don't have arguments passed in programmatically, so we need to resolve the
- // arguments specified in the constructor arguments held in the bean definition.
- ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
- resolvedValues = new ConstructorArgumentValues();
- minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
- }
- List<Exception> causes = null;
- for (int i = 0; i < candidates.length; i++) {
- Method candidate = candidates[i];
- Class[] paramTypes = candidate.getParameterTypes();
- if (paramTypes.length >= minNrOfArgs) {
- ArgumentsHolder argsHolder;
- if (resolvedValues != null) {
- // Resolved constructor arguments: type conversion and/or autowiring necessary.
- try {
- String[] paramNames = null;
- ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
- if (pnd != null) {
- paramNames = pnd.getParameterNames(candidate);
- }
- argsHolder = createArgumentArray(
- beanName, mbd, resolvedValues, bw, paramTypes, paramNames, candidate, autowiring);
- }
- catch (UnsatisfiedDependencyException ex) {
- if (this.beanFactory.logger.isTraceEnabled()) {
- this.beanFactory.logger.trace("Ignoring factory method [" + candidate +
- "] of bean '" + beanName + "': " + ex);
- }
- if (i == candidates.length - 1 && argsHolderToUse == null) {
- if (causes != null) {
- for (Exception cause : causes) {
- this.beanFactory.onSuppressedException(cause);
- }
- }
- throw ex;
- }
- else {
- // Swallow and try next overloaded factory method.
- if (causes == null) {
- causes = new LinkedList<Exception>();
- }
- causes.add(ex);
- continue;
- }
- }
- }
- else {
- // Explicit arguments given -> arguments length must match exactly.
- if (paramTypes.length != explicitArgs.length) {
- continue;
- }
- argsHolder = new ArgumentsHolder(explicitArgs);
- }
- int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
- argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
- // Choose this factory method if it represents the closest match.
- if (typeDiffWeight < minTypeDiffWeight) {
- factoryMethodToUse = candidate;
- argsHolderToUse = argsHolder;
- argsToUse = argsHolder.arguments;
- minTypeDiffWeight = typeDiffWeight;
- ambiguousFactoryMethods = null;
- }
- else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight) {
- if (ambiguousFactoryMethods == null) {
- ambiguousFactoryMethods = new LinkedHashSet<Method>();
- ambiguousFactoryMethods.add(factoryMethodToUse);
- }
- ambiguousFactoryMethods.add(candidate);
- }
- }
- }
- if (factoryMethodToUse == null) {
- boolean hasArgs = (resolvedValues.getArgumentCount() > 0);
- String argDesc = "";
- if (hasArgs) {
- List<String> argTypes = new ArrayList<String>();
- for (ValueHolder value : resolvedValues.getIndexedArgumentValues().values()) {
- String argType = (value.getType() != null ?
- ClassUtils.getShortName(value.getType()) : value.getValue().getClass().getSimpleName());
- argTypes.add(argType);
- }
- argDesc = StringUtils.collectionToCommaDelimitedString(argTypes);
- }
- throw new BeanCreationException(mbd.getResourceDescription(), beanName,
- "No matching factory method found: " +
- (mbd.getFactoryBeanName() != null ?
- "factory bean '" + mbd.getFactoryBeanName() + "'; " : "") +
- "factory method '" + mbd.getFactoryMethodName() + "(" + argDesc + ")'. " +
- "Check that a method with the specified name " +
- (hasArgs ? "and arguments " : "") +
- "exists and that it is " +
- (isStatic ? "static" : "non-static") + ".");
- }
- else if (void.class.equals(factoryMethodToUse.getReturnType())) {
- throw new BeanCreationException(mbd.getResourceDescription(), beanName,
- "Invalid factory method '" + mbd.getFactoryMethodName() +
- "': needs to have a non-void return type!");
- }
- else if (ambiguousFactoryMethods != null && !mbd.isLenientConstructorResolution()) {
- throw new BeanCreationException(mbd.getResourceDescription(), beanName,
- "Ambiguous factory method matches found in bean '" + beanName + "' " +
- "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
- ambiguousFactoryMethods);
- }
- if (explicitArgs == null && argsHolderToUse != null) {
- argsHolderToUse.storeCache(mbd, factoryMethodToUse);
- }
- }
- try {
- Object beanInstance;
- if (System.getSecurityManager() != null) {
- final Object fb = factoryBean;
- final Method factoryMethod = factoryMethodToUse;
- final Object[] args = argsToUse;
- beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
- public Object run() {
- return beanFactory.getInstantiationStrategy().instantiate(
- mbd, beanName, beanFactory, fb, factoryMethod, args);
- }
- }, beanFactory.getAccessControlContext());
- }
- else {
- beanInstance = beanFactory.getInstantiationStrategy().instantiate(
- mbd, beanName, beanFactory, factoryBean, factoryMethodToUse, argsToUse);
- }
- if (beanInstance == null) {
- return null;
- }
- bw.setWrappedInstance(beanInstance);
- return bw;
- }
- catch (Throwable ex) {
- throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
- }
- }
构造函数方式:
- /**
- * "autowire constructor" (with constructor arguments by type) behavior.
- * Also applied if explicit constructor argument values are specified,
- * matching all remaining arguments with beans from the bean factory.
- * <p>This corresponds to constructor injection: In this mode, a Spring
- * bean factory is able to host components that expect constructor-based
- * dependency resolution.
- * @param beanName the name of the bean
- * @param mbd the merged bean definition for the bean
- * @param chosenCtors chosen candidate constructors (or <code>null</code> if none)
- * @param explicitArgs argument values passed in programmatically via the getBean method,
- * or <code>null</code> if none (-> use constructor argument values from bean definition)
- * @return a BeanWrapper for the new instance
- */
- public BeanWrapper autowireConstructor(
- final String beanName, final RootBeanDefinition mbd, Constructor[] chosenCtors, final Object[] explicitArgs) {
- BeanWrapperImpl bw = new BeanWrapperImpl();
- this.beanFactory.initBeanWrapper(bw);
- Constructor constructorToUse = null;
- ArgumentsHolder argsHolderToUse = null;
- Object[] argsToUse = null;
- if (explicitArgs != null) {
- argsToUse = explicitArgs;
- }
- else {
- Object[] argsToResolve = null;
- synchronized (mbd.constructorArgumentLock) {
- constructorToUse = (Constructor) mbd.resolvedConstructorOrFactoryMethod;
- if (constructorToUse != null && mbd.constructorArgumentsResolved) {
- // Found a cached constructor...
- argsToUse = mbd.resolvedConstructorArguments;
- if (argsToUse == null) {
- argsToResolve = mbd.preparedConstructorArguments;
- }
- }
- }
- if (argsToResolve != null) {
- argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve);
- }
- }
- if (constructorToUse == null) {
- // Need to resolve the constructor.
- boolean autowiring = (chosenCtors != null ||
- mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
- ConstructorArgumentValues resolvedValues = null;
- int minNrOfArgs;
- if (explicitArgs != null) {
- minNrOfArgs = explicitArgs.length;
- }
- else {
- ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
- resolvedValues = new ConstructorArgumentValues();
- minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
- }
- // Take specified constructors, if any.
- Constructor[] candidates = chosenCtors;
- if (candidates == null) {
- Class beanClass = mbd.getBeanClass();
- try {
- candidates = (mbd.isNonPublicAccessAllowed() ?
- beanClass.getDeclaredConstructors() : beanClass.getConstructors());
- }
- catch (Throwable ex) {
- throw new BeanCreationException(mbd.getResourceDescription(), beanName,
- "Resolution of declared constructors on bean Class [" + beanClass.getName() +
- "] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
- }
- }
- AutowireUtils.sortConstructors(candidates);
- int minTypeDiffWeight = Integer.MAX_VALUE;
- Set<Constructor> ambiguousConstructors = null;
- List<Exception> causes = null;
- for (int i = 0; i < candidates.length; i++) {
- Constructor<?> candidate = candidates[i];
- Class[] paramTypes = candidate.getParameterTypes();
- if (constructorToUse != null && argsToUse.length > paramTypes.length) {
- // Already found greedy constructor that can be satisfied ->
- // do not look any further, there are only less greedy constructors left.
- break;
- }
- if (paramTypes.length < minNrOfArgs) {
- continue;
- }
- ArgumentsHolder argsHolder;
- if (resolvedValues != null) {
- try {
- String[] paramNames = null;
- if (constructorPropertiesAnnotationAvailable) {
- paramNames = ConstructorPropertiesChecker.evaluateAnnotation(candidate, paramTypes.length);
- }
- if (paramNames == null) {
- ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
- if (pnd != null) {
- paramNames = pnd.getParameterNames(candidate);
- }
- }
- argsHolder = createArgumentArray(
- beanName, mbd, resolvedValues, bw, paramTypes, paramNames, candidate, autowiring);
- }
- catch (UnsatisfiedDependencyException ex) {
- if (this.beanFactory.logger.isTraceEnabled()) {
- this.beanFactory.logger.trace(
- "Ignoring constructor [" + candidate + "] of bean '" + beanName + "': " + ex);
- }
- if (i == candidates.length - 1 && constructorToUse == null) {
- if (causes != null) {
- for (Exception cause : causes) {
- this.beanFactory.onSuppressedException(cause);
- }
- }
- throw ex;
- }
- else {
- // Swallow and try next constructor.
- if (causes == null) {
- causes = new LinkedList<Exception>();
- }
- causes.add(ex);
- continue;
- }
- }
- }
- else {
- // Explicit arguments given -> arguments length must match exactly.
- if (paramTypes.length != explicitArgs.length) {
- continue;
- }
- argsHolder = new ArgumentsHolder(explicitArgs);
- }
- int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
- argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
- // Choose this constructor if it represents the closest match.
- if (typeDiffWeight < minTypeDiffWeight) {
- constructorToUse = candidate;
- argsHolderToUse = argsHolder;
- argsToUse = argsHolder.arguments;
- minTypeDiffWeight = typeDiffWeight;
- ambiguousConstructors = null;
- }
- else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
- if (ambiguousConstructors == null) {
- ambiguousConstructors = new LinkedHashSet<Constructor>();
- ambiguousConstructors.add(constructorToUse);
- }
- ambiguousConstructors.add(candidate);
- }
- }
- if (constructorToUse == null) {
- throw new BeanCreationException(mbd.getResourceDescription(), beanName,
- "Could not resolve matching constructor " +
- "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)");
- }
- else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) {
- throw new BeanCreationException(mbd.getResourceDescription(), beanName,
- "Ambiguous constructor matches found in bean '" + beanName + "' " +
- "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
- ambiguousConstructors);
- }
- if (explicitArgs == null) {
- argsHolderToUse.storeCache(mbd, constructorToUse);
- }
- }
- try {
- Object beanInstance;
- if (System.getSecurityManager() != null) {
- final Constructor ctorToUse = constructorToUse;
- final Object[] argumentsToUse = argsToUse;
- beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
- public Object run() {
- return beanFactory.getInstantiationStrategy().instantiate(
- mbd, beanName, beanFactory, ctorToUse, argumentsToUse);
- }
- }, beanFactory.getAccessControlContext());
- }
- else {
- beanInstance = this.beanFactory.getInstantiationStrategy().instantiate(
- mbd, beanName, this.beanFactory, constructorToUse, argsToUse);
- }
- bw.setWrappedInstance(beanInstance);
- return bw;
- }
- catch (Throwable ex) {
- throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
- }
- }
采用默认构造函数方式(这也是spring默认的形式)主要看看这个的代码:
- /**
- * Instantiate the given bean using its default constructor.
- * @param beanName the name of the bean
- * @param mbd the bean definition for the bean
- * @return BeanWrapper for the new instance
- */
- 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>() {
- 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);
- }
- }
继续跟踪比较核心的getInstantiationStrategy().instantiate(mbd, beanName, parent):
- /**
- * Simple object instantiation strategy for use in a BeanFactory.
- *
- * <p>Does not support Method Injection, although it provides hooks for subclasses
- * to override to add Method Injection support, for example by overriding methods.
- *
- * @author Rod Johnson
- * @author Juergen Hoeller
- * @since 1.1
- */
- public class SimpleInstantiationStrategy implements InstantiationStrategy {
- public Object instantiate(RootBeanDefinition beanDefinition, String beanName, BeanFactory owner) {
- // Don't override the class with CGLIB if no overrides.
- if (beanDefinition.getMethodOverrides().isEmpty()) {
- Constructor<?> constructorToUse;
- synchronized (beanDefinition.constructorArgumentLock) {
- constructorToUse = (Constructor<?>) beanDefinition.resolvedConstructorOrFactoryMethod;
- if (constructorToUse == null) {
- final Class clazz = beanDefinition.getBeanClass();
- if (clazz.isInterface()) {
- throw new BeanInstantiationException(clazz, "Specified class is an interface");
- }
- try {
- if (System.getSecurityManager() != null) {
- constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor>() {
- public Constructor run() throws Exception {
- return clazz.getDeclaredConstructor((Class[]) null);
- }
- });
- }
- else {
- constructorToUse = clazz.getDeclaredConstructor((Class[]) null);
- }
- beanDefinition.resolvedConstructorOrFactoryMethod = constructorToUse;
- }
- catch (Exception ex) {
- throw new BeanInstantiationException(clazz, "No default constructor found", ex);
- }
- }
- }
- return BeanUtils.instantiateClass(constructorToUse);
- }
- else {
- // Must generate CGLIB subclass.
- return instantiateWithMethodInjection(beanDefinition, beanName, owner);
- }
- }
最后一句return instantiateWithMethodInjection(beanDefinition, beanName, owner);便是采用CGLIB的方式。上面的代码BeanUtils.instantiateClass(constructorToUse);是使用构造器或生成对象的工厂方法来实例化。
cglib代码包结构
(是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。Hibernate用它来实现PO(Persistent Object 持久化对象)字节码的动态生成。)
- core (核心代码)
- EmitUtils
- ReflectUtils
- KeyFactory
- ClassEmitter/CodeEmitter
- NamingPolicy/DefaultNamingPolicy
- GeneratorStrategy/DefaultGeneratorStrategy
- DebuggingClassWriter
- ClassGenerator/AbstractClassGenerator
- beans (bean操作类)
- BeanCopier
- BulkBean
- BeanMap
- ImmutableBean
- BeanGenerator
- reflect
- FastClass
- proxy
- MethodInterceptor , Dispatcher, LazyLoader , ProxyRefDispatcher , NoOp , FixedValue , InvocationHandler(提供和jdk proxy的功能)
- Enhancer
- CallbackGenerator
- Callback
- CallbackFilter
- util
- StringSwitcher
- ParallelSorter
- transform
继续跟踪具体的cglib实例化bean的代码:
- /**
- * Create a new instance of a dynamically generated subclasses implementing the
- * required lookups.
- * @param ctor constructor to use. If this is <code>null</code>, use the
- * no-arg constructor (no parameterization, or Setter Injection)
- * @param args arguments to use for the constructor.
- * Ignored if the ctor parameter is <code>null</code>.
- * @return new instance of the dynamically generated class
- */
- public Object instantiate(Constructor ctor, Object[] args) {
- Enhancer enhancer = new Enhancer();
- enhancer.setSuperclass(this.beanDefinition.getBeanClass());
- enhancer.setCallbackFilter(new CallbackFilterImpl());
- enhancer.setCallbacks(new Callback[] {
- NoOp.INSTANCE,
- new LookupOverrideMethodInterceptor(),
- new ReplaceOverrideMethodInterceptor()
- });
- return (ctor == null) ?
- enhancer.create() :
- enhancer.create(ctor.getParameterTypes(), args);
- }
跟踪一下BeanUtils.instantiateClass(constructorToUse);
- /**
- * Convenience method to instantiate a class using the given constructor.
- * As this method doesn't try to load classes by name, it should avoid
- * class-loading issues.
- * <p>Note that this method tries to set the constructor accessible
- * if given a non-accessible (that is, non-public) constructor.
- * @param ctor the constructor to instantiate
- * @param args the constructor arguments to apply
- * @return the new instance
- * @throws BeanInstantiationException if the bean cannot be instantiated
- */
- public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
- Assert.notNull(ctor, "Constructor must not be null");
- try {
- ReflectionUtils.makeAccessible(ctor);
- return ctor.newInstance(args);
- }
- catch (InstantiationException ex) {
- throw new BeanInstantiationException(ctor.getDeclaringClass(),
- "Is it an abstract class?", ex);
- }
- catch (IllegalAccessException ex) {
- throw new BeanInstantiationException(ctor.getDeclaringClass(),
- "Is the constructor accessible?", ex);
- }
- catch (IllegalArgumentException ex) {
- throw new BeanInstantiationException(ctor.getDeclaringClass(),
- "Illegal arguments for constructor", ex);
- }
- catch (InvocationTargetException ex) {
- throw new BeanInstantiationException(ctor.getDeclaringClass(),
- "Constructor threw exception", ex.getTargetException());
- }
- }
用到了Reflection类,是使用了反射。
- /**
- * Uses the constructor represented by this {@code Constructor} object to
- * create and initialize a new instance of the constructor's
- * declaring class, with the specified initialization parameters.
- * Individual parameters are automatically unwrapped to match
- * primitive formal parameters, and both primitive and reference
- * parameters are subject to method invocation conversions as necessary.
- *
- * <p>If the number of formal parameters required by the underlying constructor
- * is 0, the supplied {@code initargs} array may be of length 0 or null.
- *
- * <p>If the constructor's declaring class is an inner class in a
- * non-static context, the first argument to the constructor needs
- * to be the enclosing instance; see section 15.9.3 of
- * <cite>The Java™ Language Specification</cite>.
- *
- * <p>If the required access and argument checks succeed and the
- * instantiation will proceed, the constructor's declaring class
- * is initialized if it has not already been initialized.
- *
- * <p>If the constructor completes normally, returns the newly
- * created and initialized instance.
- *
- * @param initargs array of objects to be passed as arguments to
- * the constructor call; values of primitive types are wrapped in
- * a wrapper object of the appropriate type (e.g. a {@code float}
- * in a {@link java.lang.Float Float})
- *
- * @return a new object created by calling the constructor
- * this object represents
- *
- * @exception IllegalAccessException if this {@code Constructor} object
- * is enforcing Java language access control and the underlying
- * constructor is inaccessible.
- * @exception IllegalArgumentException if the number of actual
- * and formal parameters differ; if an unwrapping
- * conversion for primitive arguments fails; or if,
- * after possible unwrapping, a parameter value
- * cannot be converted to the corresponding formal
- * parameter type by a method invocation conversion; if
- * this constructor pertains to an enum type.
- * @exception InstantiationException if the class that declares the
- * underlying constructor represents an abstract class.
- * @exception InvocationTargetException if the underlying constructor
- * throws an exception.
- * @exception ExceptionInInitializerError if the initialization provoked
- * by this method fails.
- */
- @CallerSensitive
- public T newInstance(Object ... initargs)
- throws InstantiationException, IllegalAccessException,
- IllegalArgumentException, InvocationTargetException
- {
- if (!override) {
- if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
- Class<?> caller = Reflection.getCallerClass();
- checkAccess(caller, clazz, null, modifiers);
- }
- }
- if ((clazz.getModifiers() & Modifier.ENUM) != 0)
- throw new IllegalArgumentException("Cannot reflectively create enum objects");
- ConstructorAccessor ca = constructorAccessor; // read volatile
- if (ca == null) {
- ca = acquireConstructorAccessor();
- }
- return (T) ca.newInstance(initargs);
- }
之后终于看到了populateBean这个方法,之前也说过,这是用来处理依赖关系的。在AbstractAutowireCapableBeanFactory类中:
- /**
- * Populate the bean instance in the given BeanWrapper with the property values
- * from the bean definition.
- * @param beanName the name of the bean
- * @param mbd the bean definition for the bean
- * @param bw BeanWrapper with bean instance
- */
- protected void populateBean(String beanName, AbstractBeanDefinition 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 {
- // Skip property population phase for null instance.
- return;
- }
- }
- // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
- // state of the bean before properties are set. This can be used, for example,
- // to support styles of field injection.
- 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);
- // Add property values based on autowire by name if applicable.
- if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
- autowireByName(beanName, mbd, bw, newPvs);
- }
- // Add property values based on autowire by type if applicable.
- 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);
- 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);
- }
设断点单步跟踪,可知PropertyValues pvs = mbd.getPropertyValues();这句是获取该bean的所有属性。
真正核心的是最后这句,其中PropertyValues pvs作为其参数:
- /**
- * Apply the given property values, resolving any runtime references
- * to other beans in this bean factory. Must use deep copy, so we
- * don't permanently modify this property.
- * @param beanName the bean name passed for better exception information
- * @param mbd the merged bean definition
- * @param bw the BeanWrapper wrapping the target object
- * @param pvs the new property values
- */
- protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
- if (pvs == null || pvs.isEmpty()) {
- return;
- }
- MutablePropertyValues mpvs = null;
- List<PropertyValue> original;
- if (System.getSecurityManager()!= null) {
- if (bw instanceof BeanWrapperImpl) {
- ((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
- }
- }
- if (pvs instanceof MutablePropertyValues) {
- mpvs = (MutablePropertyValues) pvs;
- if (mpvs.isConverted()) {
- // Shortcut: use the pre-converted values as-is.
- try {
- bw.setPropertyValues(mpvs);
- return;
- }
- catch (BeansException ex) {
- throw new BeanCreationException(
- mbd.getResourceDescription(), beanName, "Error setting property values", ex);
- }
- }
- original = mpvs.getPropertyValueList();
- }
- else {
- original = Arrays.asList(pvs.getPropertyValues());
- }
- TypeConverter converter = getCustomTypeConverter();
- if (converter == null) {
- converter = bw;
- }
- BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
- // Create a deep copy, resolving any references for values.
- List<PropertyValue> deepCopy = new ArrayList<PropertyValue>(original.size());
- boolean resolveNecessary = false;
- for (PropertyValue pv : original) {
- if (pv.isConverted()) {
- deepCopy.add(pv);
- }
- else {
- String propertyName = pv.getName();
- Object originalValue = pv.getValue();
- Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
- Object convertedValue = resolvedValue;
- boolean convertible = bw.isWritableProperty(propertyName) &&
- !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
- if (convertible) {
- convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
- }
- // Possibly store converted value in merged bean definition,
- // in order to avoid re-conversion for every created bean instance.
- if (resolvedValue == originalValue) {
- if (convertible) {
- pv.setConvertedValue(convertedValue);
- }
- deepCopy.add(pv);
- }
- else if (convertible && originalValue instanceof TypedStringValue &&
- !((TypedStringValue) originalValue).isDynamic() &&
- !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
- pv.setConvertedValue(convertedValue);
- deepCopy.add(pv);
- }
- else {
- resolveNecessary = true;
- deepCopy.add(new PropertyValue(pv, convertedValue));
- }
- }
- }
- if (mpvs != null && !resolveNecessary) {
- mpvs.setConverted();
- }
- // Set our (possibly massaged) deep copy.
- try {
- bw.setPropertyValues(new MutablePropertyValues(deepCopy));
- }
- catch (BeansException ex) {
- throw new BeanCreationException(
- mbd.getResourceDescription(), beanName, "Error setting property values", ex);
- }
- }
- /**
- * Convert the given value for the specified target property.
- */
- private Object convertForProperty(Object value, String propertyName, BeanWrapper bw, TypeConverter converter) {
- if (converter instanceof BeanWrapperImpl) {
- return ((BeanWrapperImpl) converter).convertForProperty(value, propertyName);
- }
- else {
- PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
- MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
- return converter.convertIfNecessary(value, pd.getPropertyType(), methodParam);
- }
- }
这个方法很长,其内在逻辑却也不难。主要是对传进来的PropertyValues pvs参数的每一项做一个解析过程,而BeanWrapper bw参数包装着前面实例化的bean实例对象。
而BeanDefinition mbd这个参数,也就是BeanDefinition,在这里只用于抛出异常信息,没什么大用。
看代码for (PropertyValue pv : original) {}循环遍历PropertyValues,循环过程解析每一个字段:Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue),最后bw.setPropertyValues(new MutablePropertyValues(deepCopy));这句将之前得到的结果set进我们要处理的实例化对象;
- /**
- * Given a PropertyValue, return a value, resolving any references to other
- * beans in the factory if necessary. The value could be:
- * <li>A BeanDefinition, which leads to the creation of a corresponding
- * new bean instance. Singleton flags and names of such "inner beans"
- * are always ignored: Inner beans are anonymous prototypes.
- * <li>A RuntimeBeanReference, which must be resolved.
- * <li>A ManagedList. This is a special collection that may contain
- * RuntimeBeanReferences or Collections that will need to be resolved.
- * <li>A ManagedSet. May also contain RuntimeBeanReferences or
- * Collections that will need to be resolved.
- * <li>A ManagedMap. In this case the value may be a RuntimeBeanReference
- * or Collection that will need to be resolved.
- * <li>An ordinary object or <code>null</code>, in which case it's left alone.
- * @param argName the name of the argument that the value is defined for
- * @param value the value object to resolve
- * @return the resolved object
- */
- public Object resolveValueIfNecessary(Object argName, Object value) {
- // We must check each value to see whether it requires a runtime reference
- // to another bean to be resolved.
- if (value instanceof RuntimeBeanReference) {
- RuntimeBeanReference ref = (RuntimeBeanReference) value;
- return resolveReference(argName, ref);
- }
- else if (value instanceof RuntimeBeanNameReference) {
- String refName = ((RuntimeBeanNameReference) value).getBeanName();
- refName = String.valueOf(evaluate(refName));
- if (!this.beanFactory.containsBean(refName)) {
- throw new BeanDefinitionStoreException(
- "Invalid bean name '" + refName + "' in bean reference for " + argName);
- }
- return refName;
- }
- else if (value instanceof BeanDefinitionHolder) {
- // Resolve BeanDefinitionHolder: contains BeanDefinition with name and aliases.
- BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value;
- return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition());
- }
- else if (value instanceof BeanDefinition) {
- // Resolve plain BeanDefinition, without contained name: use dummy name.
- BeanDefinition bd = (BeanDefinition) value;
- return resolveInnerBean(argName, "(inner bean)", bd);
- }
- else if (value instanceof ManagedArray) {
- // May need to resolve contained runtime references.
- ManagedArray array = (ManagedArray) value;
- Class elementType = array.resolvedElementType;
- if (elementType == null) {
- String elementTypeName = array.getElementTypeName();
- if (StringUtils.hasText(elementTypeName)) {
- try {
- elementType = ClassUtils.forName(elementTypeName, this.beanFactory.getBeanClassLoader());
- array.resolvedElementType = elementType;
- }
- catch (Throwable ex) {
- // Improve the message by showing the context.
- throw new BeanCreationException(
- this.beanDefinition.getResourceDescription(), this.beanName,
- "Error resolving array type for " + argName, ex);
- }
- }
- else {
- elementType = Object.class;
- }
- }
- return resolveManagedArray(argName, (List<?>) value, elementType);
- }
- else if (value instanceof ManagedList) {
- // May need to resolve contained runtime references.
- return resolveManagedList(argName, (List<?>) value);
- }
- else if (value instanceof ManagedSet) {
- // May need to resolve contained runtime references.
- return resolveManagedSet(argName, (Set<?>) value);
- }
- else if (value instanceof ManagedMap) {
- // May need to resolve contained runtime references.
- return resolveManagedMap(argName, (Map<?, ?>) value);
- }
- else if (value instanceof ManagedProperties) {
- Properties original = (Properties) value;
- Properties copy = new Properties();
- for (Map.Entry propEntry : original.entrySet()) {
- Object propKey = propEntry.getKey();
- Object propValue = propEntry.getValue();
- if (propKey instanceof TypedStringValue) {
- propKey = evaluate((TypedStringValue) propKey);
- }
- if (propValue instanceof TypedStringValue) {
- propValue = evaluate((TypedStringValue) propValue);
- }
- copy.put(propKey, propValue);
- }
- return copy;
- }
- else if (value instanceof TypedStringValue) {
- // Convert value to target type here.
- TypedStringValue typedStringValue = (TypedStringValue) value;
- Object valueObject = evaluate(typedStringValue);
- try {
- Class<?> resolvedTargetType = resolveTargetType(typedStringValue);
- if (resolvedTargetType != null) {
- return this.typeConverter.convertIfNecessary(valueObject, resolvedTargetType);
- }
- else {
- return valueObject;
- }
- }
- catch (Throwable ex) {
- // Improve the message by showing the context.
- throw new BeanCreationException(
- this.beanDefinition.getResourceDescription(), this.beanName,
- "Error converting typed String value for " + argName, ex);
- }
- }
- else {
- return evaluate(value);
- }
- }
简单总结:
一、容器初始化:
1,Resource来进行资源定位
2,spring创建工厂时(以XmlBeanFactory为例),解析xml文件,转化为document
3,注册BeanDefinition,在BeanFactory的map数据结构里。BeanDefinition就是spring内部用来描绘bean的数据结构
4,getBean时,依据BeanDefinition,实例化对象
5, populateBean 处理 前面实例化的对象的依赖关系
spring源码分析(一)IoC、DI的更多相关文章
- 【spring源码分析】IOC容器初始化(总结)
前言:在经过前面十二篇文章的分析,对bean的加载流程大致梳理清楚了.因为内容过多,因此需要进行一个小总结. 经过前面十二篇文章的漫长分析,终于将xml配置文件中的bean,转换成我们实际所需要的真正 ...
- 【spring源码分析】IOC容器初始化(二)
前言:在[spring源码分析]IOC容器初始化(一)文末中已经提出loadBeanDefinitions(DefaultListableBeanFactory)的重要性,本文将以此为切入点继续分析. ...
- 【spring源码分析】IOC容器初始化(三)
前言:在[spring源码分析]IOC容器初始化(二)中已经得到了XML配置文件的Document实例,下面分析bean的注册过程. XmlBeanDefinitionReader#registerB ...
- 【spring源码分析】IOC容器初始化(四)
前言:在[spring源码分析]IOC容器初始化(三)中已经分析了BeanDefinition注册之前的一些准备工作,下面将进入BeanDefinition注册的核心流程. //DefaultBean ...
- 【spring源码分析】IOC容器初始化(七)
前言:在[spring源码分析]IOC容器初始化(六)中分析了从单例缓存中加载bean对象,由于篇幅原因其核心函数 FactoryBeanRegistrySupport#getObjectFromFa ...
- 【spring源码分析】IOC容器初始化(十)
前言:前文[spring源码分析]IOC容器初始化(九)中分析了AbstractAutowireCapableBeanFactory#createBeanInstance方法中通过工厂方法创建bean ...
- 【spring源码分析】IOC容器初始化——查漏补缺(一)
前言:在[spring源码分析]IOC容器初始化(十一)中提到了初始化bean的三个步骤: 激活Aware方法. 后置处理器应用(before/after). 激活自定义的init方法. 这里我们就来 ...
- Spring源码分析专题 —— IOC容器启动过程(上篇)
声明 1.建议先阅读<Spring源码分析专题 -- 阅读指引> 2.强烈建议阅读过程中要参照调用过程图,每篇都有其对应的调用过程图 3.写文不易,转载请标明出处 前言 关于 IOC 容器 ...
- Spring源码分析之IOC的三种常见用法及源码实现(二)
Spring源码分析之IOC的三种常见用法及源码实现(二) 回顾上文 我们研究的是 AnnotationConfigApplicationContext annotationConfigApplica ...
- 【spring源码分析】IOC容器初始化——查漏补缺(五)
前言:我们知道在Spring中经常使用配置文件的形式对进行属性的赋值,那配置文件的值是怎么赋值到属性上的呢,本文将对其进行分析. 首先了解一个类:PropertySourcesPlaceholderC ...
随机推荐
- [C#.NET]
Control.Refresh - does an Control.Invalidate followed by Control.Update. Refresh: 强制控件使其工作区无效并立即重绘自己 ...
- java安装教程
1.安装中,jdk和jre的安装在不同的目录中 2.环境变量的配置 选择系统变量中 新建以下3个环境变量: JAVA_HOME jdk安装路径 CLASSPATH .;%JAVA_HOME%\li ...
- Process 执行shell 脚本
概述: Process类是一个抽象类(所有的方法均是抽象的),封装了一个进程(即一个执行程序). Process 类提供了执行从进程输入.执行输出到进程.等待进程完成.检查进程的退出状态以及销毁(杀掉 ...
- Qt 5.7设置调试器
mingw版本下自带的,这个我就不在赘述. 现在来说一下msvc版本下调试器,cdb,这个需要到ms去下载. thunder://QUFodHRwOi8vZG93bmxvYWQubWljcm9zb2Z ...
- yii 图片展示
<?= DetailView::widget([ 'model' => $model, 'attributes' => [ 'id', 'name', 'time', 'pic', ...
- hdu 1342(DFS)
Lotto Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submi ...
- Struts2之文件上传下载
本篇文章主要介绍如何利用struts2进行文件的上传及下载,同时给出我在编写同时所遇到的一些问题的解决方案. 文件上传 前端页面 <!-- 引入struts标签 --> <%@tag ...
- Java程序,求学员的平均成绩
第一步,系统提示输入学员的人数. 第二步,逐一获取学员的分数,并累计. 第三步,求平均成绩,并输出. import java.util.Scanner; public class chengji { ...
- C# IGUID的生成
GUID(全局统一标识符)是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的.通常平台会提供生成GUID的API.生成算法很有意思,用到了以太网卡地址.纳秒级时间.芯片ID码和许多可 ...
- WIN8 平台应用隐私声明
隐私权声明 本应用连接网络仅为控制硬件设备,不会收集你的个人信息,也不共享你个个人信息. 应用名称 雅典娜监控平台移动客户端 关于本应用 本应仅为控制设备应用,不关注任何配置相关信息,所有数据均来自服 ...