文档章节

Spring源码解析(六)——实例创建(上)

MarvelCode
 MarvelCode
发布于 06/19 19:56
字数 3014
阅读 11
收藏 1
点赞 0
评论 0

前言

    经过前期所有的准备工作,Spring已经获取到需要创建实例的 beanName 和对应创建所需要信息 BeanDefinition,接下来就是实例创建的过程,由于该过程涉及到大量源码,所以将分为多个章节进行解读,这里面同样隐藏了 Bean 生命周期相关接口的执行。

 

源码解读

    首先来看看实例创建的源头。

public abstract class AbstractApplicationContext extends DefaultResourceLoader
        implements ConfigurableApplicationContext, DisposableBean {

    protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
        ......// 省略
        // 源头在这里
        beanFactory.preInstantiateSingletons();
    }
}

    源头就是“容器刷新”的最后一步了,展开来看这个方法,由 DefaultListableBeanFactory 实现。

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
        implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {

    @Override
    public void preInstantiateSingletons() throws BeansException {
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Pre-instantiating singletons in " + this);
        }

        // 这里就是容器创建时候收集的所有 beanName
        // 见本类方法:registerBeanDefinition
        List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);

        // 遍历触发所有非惰性单例 bean的初始化...
        for (String beanName : beanNames) {
            // RootBeanDefinition可以看作是描述 bean的统一视图
            RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
            // 非抽象 & 单例 & 非惰性
            if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
                /**
                 * 是否为 FactoryBean类型:介绍下这个接口的方法
                 * - getObject:返回由FactoryBean创建的bean实例
                 * - getObjectType:返回 bean类型
                 * - isSingleton:判断是否为单例
                 */
                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());
                    }
                    // 实现了 SmartFactoryBean可以指定是否直接初始化 
                    if (isEagerInit) {
                        // 1.关注此方法
                        getBean(beanName);
                    }
                } else {
                    // 1.关注此方法
                    getBean(beanName);
                }
            }
        }

        // 回调 SmartInitializingSingleton.afterSingletonsInstantiated
        // 仅限单例,在实例化后提供一些自定义的初始化操作
        for (String beanName : beanNames) {

            // 2.关注此方法
            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();
                }
            }
        }
    }
}

    这里遍历的就是容器创建时所扫描的所有需要创建的 beanName,然后根据之前封装的 GenericBeanDefinition 来创建 RootBeanDifinition,其中 GenericBeanDefinition 的封装见 默认标签解析 的<bean>解析封装,beanName 与 GenericBeanDefinition  映射关系注册见 默认标签解析 的<bean>注册操作

    接下来,重点分析 getBean 方法,这个方法内同样用到了 getSingleton,我们逐个来看。

 

getBean

public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {

    /**
     * 已实例化的单例缓存
     */
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);

    /**
     * 与singletonObjects的不同之处,在实例创建时,就可以通过 getBean获取到,解决循环依赖
     */
    private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);

    /**
     * 保存BeanName和创建bean的工厂之间的关系
     */
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);

    /**
     * 放置正在被创建的单例
     */
    private final Set<String> singletonsCurrentlyInCreation =
            Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(16));

    /**
     * 至少创建一次的实例集合
     */
    private final Set<String> alreadyCreated =
            Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(256));

    @Override
    public Object getBean(String name) throws BeansException {
        return doGetBean(name, null, null, false);
    }

    /**
     * @param name         指定的 bean名称
     * @param requiredType bean 对应的 Class类型
     * @param args         通过构造器/工厂方法传入特定参数
     * @return 创建好的实例
     */
    protected <T> T doGetBean(final String name, final Class<T> requiredType,
                              final Object[] args, boolean typeCheckOnly) throws BeansException {

        // 别名转换:转为规范的 beanName(别名对应的真正 name)
        final String beanName = transformedBeanName(name);
        Object bean;

        // 尝试从手动注册的单例缓存中获取
        // 优先级( singletonObjects -> earlySingletonObjects )
        Object sharedInstance = getSingleton(beanName);
        if (sharedInstance != null && args == null) {
            ......// 省略日志

            // 这个方法下面会展开讲解,目前仅需要知道这个会返回实例即可
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
        }
        // 如果缓存中没有就走下面的分支
        else {
            // 循环依赖的处理:通过 ThreadLocal实现(维护了正在创建的 beanName)
            // 判断原理就是判断 beanName是否存在于指定的 ThreadLocal内
            if (isPrototypeCurrentlyInCreation(beanName)) {
                // 这里的检查只针对非 Singleton作用域
                // 因为单例有自身循环依赖的解决方案,见 getSingleton
                throw new BeanCurrentlyInCreationException(beanName);
            }

            BeanFactory parentBeanFactory = getParentBeanFactory();
            // 如果自身容器的 beanDefinitionMap不包含该 beanName,从父容器中查找.
            if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                String nameToLookup = originalBeanName(name);
                if (args != null) {
                    parentBeanFactory.getBean(nameToLookup, args);
                } else {
                    return parentBeanFactory.getBean(nameToLookup, requiredType);
                }
            }

            // 默认的 typeCheckOnly为 false,即不需要类型检查
            if (!typeCheckOnly) {
                // 标识该 beanName正在被创建(alreadyCreated存储)
                markBeanAsCreated(beanName);
            }

            try {
                // 获取统一视图:包含了所有的创建所需信息
                final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                // 校验如果是抽象类会抛出异常
                checkMergedBeanDefinition(mbd, beanName, args);

                // 是否指定了“depend-on”,如果有,则循环注册
                String[] dependsOn = mbd.getDependsOn();
                if (dependsOn != null) {
                    for (String dependsOnBean : dependsOn) {
                        // 检查是否有循环依赖
                        if (isDependent(beanName, dependsOnBean)) {
                            //....省略抛异常
                        }
                        // 这一步存储了依赖映射 Map<String, Set<String>>
                        // key-beanName,value-dependsOnBean集合
                        registerDependentBean(dependsOnBean, beanName);
                        // 然后创建 depend-on指定的 bean
                        getBean(dependsOnBean);
                    }
                }

                // 解决依赖 bean创建后,开始 bean实例真正的创建
                if (mbd.isSingleton()) {

                    // 单例:共享,通过 ObjectFactory创建
                    sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
                        @Override
                        public Object getObject() throws BeansException {
                            try {
                                // 通过 createBean创建实例,下节讲解
                                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 {
                        // ThreadLocal赋值标识该 bean正在被创建
                        // 见上述 isPrototypeCurrentlyInCreation方法
                        beforePrototypeCreation(beanName);

                        // 通过 createBean创建实例,下节讲解
                        prototypeInstance = createBean(beanName, mbd, args);
                    } finally {
                        // 移除 ThreadLocal中该 beanName
                        afterPrototypeCreation(beanName);
                    }

                    // 这个方法下面会展开讲解,目前仅需要知道这个会返回实例即可
                    bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
                } else {
                    // 其他作用域处理,获取作用域名,转化成 Scope
                    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 {
                        // 各作用域:共享,通过 ObjectFactory创建
                        Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
                            @Override
                            public Object getObject() throws BeansException {
                                // ThreadLocal赋值标识该 bean正在被创建
                                beforePrototypeCreation(beanName);
                                try {
                                    // 通过 createBean创建实例,下节讲解
                                    return createBean(beanName, mbd, args);
                                } finally {
                                    // 移除 ThreadLocal中该 beanName
                                    afterPrototypeCreation(beanName);
                                }
                            }
                        });

                        // 这个方法下面会展开讲解,目前仅需要知道这个会返回实例即可
                        bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                    } //...catch操作
                }
            } //...catch操作
            ......
        }

        // 如果传入了requiredType,则进行转型工作
        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;
    }
}

    getBean 会调用 doGetBean 来进行实例创建,这种方法的命名在 Spring 到处可见,很多 xxx 的接口会将真正处理代码传给 doXxx 方法。我们来梳理下上面做了哪些事情:

  • beanName转换:首先会将传入的 name 转化为规范的 beanName,比如我们传入别名,Spring会根据映射关系将别名转为 bean最原始的 beanName;
  • 单例缓存:见 getSingleton 方法讲解,因为单例全局唯一,所以创建一次后就缓存起来,防止重复创建,一旦在缓存中找到就直接返回了;
  • 非单例循环依赖检测:通过将正创建的 beanName 放置于 ThreadLocal 中(见 beforePrototypeCreation),在创建结束后会将 ThreadLocal 中对应 beanName 移除(见 afterPrototypeCreation), 如果创建期间发现该 beanName 还在被创建,说明该实例依赖的其他实例又依赖了自己,会抛异常;
  • 父容器获取:触发父容器获取的条件是,自身容器中没有注册对应 beanName 的 BeanDefinition,所以优先级是“子容器->父容器”;
  • depends-on处理:有些实例的创建,需要依赖其他实例先创建,所有需要在创建自身前先将这些实例创建(递归调用 getBean);
  • 创建自身:有三个分支,SingletonPrototype、其他Scope,都是调用 createBean 来创建实例,这个方法会在下节解读。
  • 类型转换:这一步根据调用 getBean 时是否传入 requireType 来进行类型转换的。

    分析完主要的逻辑,我们来接着看上面代码中出现频次比较多的两个方法 “ getSingleton ” 和 “ getObjectForBeanInstance ”。

 

getSingleton

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {

    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);

    // 保存 beanName和创建该 bean工厂之间的关系
    // 如果都没有,会使用工厂创建,创建后放入 earlySingletonObjects
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);

    // 提前曝光,为了解决循环依赖问题,在属性注入前放置
    private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);


    // 2.方法源码
    @Override
    public Object getSingleton(String beanName) {
        return getSingleton(beanName, true);
    }

    /**
     * @param beanName            指定的 bean规范名称
     * @param allowEarlyReference 是否创建早期引用(用于解决循环引用)
     * @return 注册的单例,如果没找到返回 null
     */
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        Object singletonObject = this.singletonObjects.get(beanName);
        // 判断该 bean是否在创建过程中
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            // 防并发,双重锁
            synchronized (this.singletonObjects) {
                // 缓存获取实例(还未创建完毕,提前曝光)
                singletonObject = this.earlySingletonObjects.get(beanName);
                if (singletonObject == null && allowEarlyReference) {
                    // 缓存获取工厂(用于调用 getObject获取实例)
                    ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                    if (singletonFactory != null) {
                        singletonObject = singletonFactory.getObject();
                        // earlySingletonObjects用于解决循环引用
                        this.earlySingletonObjects.put(beanName, singletonObject);
                        // 移除 singletonFactories,说明 bean完全创建好
                        this.singletonFactories.remove(beanName);
                    }
                }
            }
        }
        return (singletonObject != NULL_OBJECT ? singletonObject : null);
    }

    public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
        Assert.notNull(beanName, "'beanName' must not be null");
        // 双重锁,当缓存中不存在才可以进行单例 bean的初始化
        synchronized (this.singletonObjects) {
            Object singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {

                // singletonsCurrentlyInDestruction:标识目前容器是否在销毁 Singletons
                // 容器关闭时、或容器启动异常时会置为 true
                if (this.singletonsCurrentlyInDestruction) {
                    ....// 省略抛异常
                }
                if (logger.isDebugEnabled()) {
                    logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
                }
                // 记录加载状态:该 bean正在被创建
                beforeSingletonCreation(beanName);
                boolean newSingleton = false;
                boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
                if (recordSuppressedExceptions) {
                    this.suppressedExceptions = new LinkedHashSet<Exception>();
                }
                try {
                    // 调用 ObjectFactory.getObject() 创建
                    singletonObject = singletonFactory.getObject();
                    newSingleton = true;
                } ...// 省略 catch处理
                finally{
                    if (recordSuppressedExceptions) {
                        this.suppressedExceptions = null;
                    }
                    // 移除加载状态: bean已被创建完毕(对应 beforeSingletonCreation)
                    afterSingletonCreation(beanName);
                }
                if (newSingleton) {
                    // 将 bean放入缓存
                    addSingleton(beanName, singletonObject);
                }
            }
            return (singletonObject != NULL_OBJECT ? singletonObject : null);
        }
    }

    protected void addSingleton(String beanName, Object singletonObject) {
        synchronized (this.singletonObjects) {
            // 将已创建的实例放入缓存 singletonObjects
            this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
            // 移除 singletonFactories和 earlySingletonObjects,说明 bean完全创建好
            this.singletonFactories.remove(beanName);
            this.earlySingletonObjects.remove(beanName);
            this.registeredSingletons.add(beanName);
        }
    }

}

    这个方法有3个重载版本,逻辑不复杂,维护了几个缓存关系,还有就是 “提前曝光” 的逻辑。这里调用 ObjectFactory.getObject 获取实例,其实会回调 doGetBean 中匿名内部类实现:createBean,下章讲解。

 

getObjectForBeanInstance

public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
    
    protected Object getObjectForBeanInstance(
            Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {

        // name以"&"开头,但却不是 FactoryBean类型,抛出异常
		if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
			throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
		}
        // name不以"&"开头,也不是 FactoryBean类型,直接返回
		if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
			return beanInstance;
		}

        Object object = null;
        if (mbd == null) {
            // 尝试从缓存中(factoryBeanObjectCache)获取
            object = getCachedObjectForFactoryBean(beanName);
        }
        if (object == null) {
            // 到这里的就只有 FactoryBean类型了,强转
            FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
            // 获取统一视图,一般都是传入的,即 mbd != null
            if (mbd == null && containsBeanDefinition(beanName)) {
                mbd = getMergedLocalBeanDefinition(beanName);
            }
            // 从 FactoryBean中获取实例
            object = getObjectFromFactoryBean(factory, beanName, !synthetic);
        }
        return object;
    }

    protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
        // 单例且缓存(singletonObjects)有此实例
        if (factory.isSingleton() && containsSingleton(beanName)) {
            // getSingletonMutex返回的是 singletonObjects
            synchronized (getSingletonMutex()) {
                // 缓存中(factoryBeanObjectCache)有此实例
                Object object = this.factoryBeanObjectCache.get(beanName);
                if (object == null) {
                    // 调用 FactoryBean.getObject()
                    object = doGetObjectFromFactoryBean(factory, beanName);
                    // 锁的是 singletonObjects,factoryBeanObjectCache可能被其他线程并发放入
                    Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
                    if (alreadyThere != null) {
                        object = alreadyThere;
                    } else {
                        if (object != null && shouldPostProcess) {
                            try {
                                // 这一步由子类 AbstractAutowireCapableBeanFactory实现
                                // bean生命周期:BeanPostProcessor.postProcessAfterInitialization
                                object = postProcessObjectFromFactoryBean(object, beanName);
                            } ...// 省略 catch
                        }
                        // 只有单例才会放入缓存中(factoryBeanObjectCache)
                        this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));
                    }
                }
                return (object != NULL_OBJECT ? object : null);
            }
        } else {
            // 调用 FactoryBean.getObject()
            Object object = doGetObjectFromFactoryBean(factory, beanName);
            if (object != null && shouldPostProcess) {
                try {
                    // 这一步由子类 AbstractAutowireCapableBeanFactory实现
                    // bean生命周期:BeanPostProcessor.postProcessAfterInitialization
                    object = postProcessObjectFromFactoryBean(object, beanName);
                } ...// 省略catch
            }
            return object;
        }
    }

    private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
            throws BeanCreationException {

        Object object;
        try {
            if (System.getSecurityManager() != null) {
                AccessControlContext acc = getAccessControlContext();
                try {
                    object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
                        @Override
                        public Object run() throws Exception {
                            // 调用 FactoryBean.getObject
                            return factory.getObject();
                        }
                    }, acc);
                } catch (PrivilegedActionException pae) {
                    throw pae.getException();
                }
            } else {
                // 调用 FactoryBean.getObject
                object = factory.getObject();
            }
        } ...// 省略 catch处理

        // 实例为空处理
        if (object == null && isSingletonCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(
                    beanName, "FactoryBean which is currently in creation returned null from getObject");
        }
        return object;
    }

}

    这个方法主要值针对 FactoryBean 这种类型的处理,通过回调 FactoryBean.getObject 来获取实例。

    FactoryBean:通过 beanName 获取的是 FactoryBean.getObject,在 beanName 前面添加 “&” 符号获取 FactoryBean 本身。

    ObjectFactory:就是一个简单的实例工厂,通过 beanName 获取对应创建出的实例。

 

总结

    通过上面的源码可以看出,Spring 创建实例的时候用到了很多缓存映射,通过这些避免了重复的创建,节省了时间。接下来就是 createBean 具体的创建逻辑了。

© 著作权归作者所有

共有 人打赏支持
MarvelCode
粉丝 40
博文 27
码字总数 53412
作品 0
南京
程序员
SpringCloud Eureka 源码解析 —— 应用实例注册发现(六)之全量获取

SpringCloud Eureka 源码解析 —— 应用实例注册发现(六)之全量获取 Harries Blog™2017-12-311 阅读 ACESpringAppcacheAPIbuildAtombug 摘要: 原创出处 http ://www. ioc oder.cn/ Eureka...

Harries Blog™
2017/12/31
0
0
SpringMVC源码解析(一)——初始化

前言 本系列文章顺延“Spring源码解析”,是在“父容器”创建完成后,对“子容器”(SpringMVC)创建,以及请求处理的解析。 源码解读 说起 SpringMVC,DispatcherServlet 应该是最熟悉的类之...

MarvelCode
06/26
0
0
Dubbo 实现原理与源码解析系列 —— 精品合集

摘要: 原创出处 http://www.iocoder.cn/Dubbo/good-collection/ 「芋道源码」欢迎转载,保留摘要,谢谢! 1.【芋艿】精尽 Dubbo 原理与源码专栏 2.【老徐】RPC 专栏 3.【肥朝】Dubbo 源码解析...

芋道源码掘金Java群217878901
06/23
0
0
向Spring大佬低头——大量源码流出解析

用Spring框架做了几年的开发,只停留在会用的阶段上,然而Spring的设计思想和原理确实一个巨大的宝库。大部分人仅仅知道怎么去配,或着加上什么属性就能达到什么效果,这些东西都可以通过查文...

Java团长17
07/11
0
0
网关 Spring-Cloud-Gateway 源码解析 —— 网关初始化

网关 Spring-Cloud-Gateway 源码解析 —— 网关初始化 Harries Blog™2017-12-135 阅读 SpringAppclasspathcatbeanAPIbuildbug 本文主要基于 Spring-Cloud-Gateway 2.0.X M4 摘要: 原创出处 ......

Harries Blog™
2017/12/13
0
0
Spring MVC 解读——View,ViewResolver

上一篇文章(1)(2)分析了Spring是如何调用和执行控制器方法,以及处理返回结果的,现在我们就分析下Spring如何解析返回的结果生成响应的视图。 一、概念理解 View ---View接口表示一个响应...

麦壳原野
2014/04/12
0
1
Mybatis学习(3)—— 事务机制

事务的实现 对数据库的事务而言,应该具有以下几点:创建(create)、提交(commit)、回滚(rollback)、关闭(close)。对应地,MyBatis将事务抽象成了Transaction接口: org.apache.ibait...

叶枫啦啦
07/12
0
0
Spring源码解析系列之IOC容器(一)

前言 实际上我所有的博客都是原来对原来印象笔记里笔记内容的加工,关于Spring源码自己已经解析了很多遍,但是时间长总是忘记,写一篇博客权当加强记忆,也算再次学习下大师们的设计思想,思...

后厂村老司机
06/02
0
0
Spring对注解(Annotation)处理源码分析1——扫描和读取Bean定义

1.从Spring2.0以后的版本中,Spring也引入了基于注解(Annotation)方式的配置,注解(Annotation)是JDK1.5中引入的一个新特性,用于简化Bean的配置,某些场合可以取代XML配置文件。开发人员对注...

李长春
2011/10/08
0
0
看看Spring的源码(一)——Bean加载过程

本文发表于我的独立博客:Geeekr 最近几天跟同事聊起Spring的一些问题,对一些地方有些疑问,趁这两天有点空,看看Spring的源码,了解下具体的实现细节。本文基于Spring 4.0.5版本。 首先Web...

gongzili
2014/08/18
0
7

没有更多内容

加载失败,请刷新页面

加载更多

下一页

垃圾回收算法

一 如何判断对象可以回收 1 引用计数法 思路大概为:给对象添加一个引用计数器,每当有一个地方引用它时,计数器值加1;当引用失效时,计数器减1;任何时刻计算器为0的对象就是不可能再被使用...

sen_ye
5分钟前
0
0
Activiti简介(学习总结一)

一、介绍 activiti是使用命令模式设计基于bpmn2.0的一款开源工作流引擎。 工作流简单举例:提交请假申请->经理审批->结束。这就是一个简单流程。activiti支持用户自定义流程。配置各个流程对...

沙shasha
5分钟前
0
0
VCL界面控件DevExpress VCL Controls发布v18.1.3|附下载

DevExpress VCL Controls是 Devexpress公司旗下最老牌的用户界面套包。所包含的控件有:数据录入,图表,数据分析,导航,布局,网格,日程管理,样式,打印和工作流等,让您快速开发出完美、...

Miss_Hello_World
6分钟前
0
0
加米谷大数据培训:云计算、大数据和人工智能之间的关系

一般谈云计算的时候会提到大数据、谈人工智能的时候会提大数据、谈人工智能的时候会提云计算……感觉三者之间相辅相成又不可分割。 一、云计算最初的目标 云计算最初的目标是对资源的管理,管...

加米谷大数据
11分钟前
1
0
java集合元素的默认大小

当底层实现涉及到扩容时,容器或重新分配一段更大的连续内存(如果是离散分配则不需要重新分配,离散分配都是插入新元素时动态分配内存),要将容器原来的数据全部复制到新的内存上,这无疑使...

竹叶青出于蓝
14分钟前
1
0
Java快速开发平台,JEECG 3.7.7闪电版本发布,增加多套主流UI代码生成器模板

JEECG 3.7.7 闪电版本发布,提供5套主流UI代码生成器模板 导读 ⊙平台性能优化,速度闪电般提升 ⊙提供5套新的主流UI代码生成器模板(Bootstrap表单+BootstrapTable列表\ ElementUI列表表单)...

Jeecg
17分钟前
0
0
export 和 module.export 的区别

在浏览器端 js 里面,为了解决各模块变量冲突等问题,往往借助于 js 的闭包把左右模块相关的代码都包装在一个匿名函数里。而 Nodejs 编写模块相当的自由,开发者只需要关注 require,exports,...

孟飞阳
19分钟前
1
0
技术教育的兴起

技术教育的兴起 作者: 阮一峰 1、 有一年,我在台湾环岛旅行。 花莲的海边,我遇到一对台湾青年夫妻,带着女儿在海滩上玩。我们聊了起来。 当时,我还在高校当老师。他们问我,是否觉得台湾...

吕伯文
19分钟前
0
0
Linux服务器下的HTTP抓包分析

说到抓包分析,最简单的办法莫过于在客户端直接安装一个Wireshark或者Fiddler了,但是有时候由于客户端开发人员(可能是第三方)知识欠缺或者其它一些原因,无法顺利的在客户端进行抓包分析,...

mylxsw
24分钟前
0
0
mybatis3-javaapi

sqlSessionFactoryBuilder->sqlSessionFactory->sqlSession<-rowbound<-resultHandler myBatis uses a Java enumeration wrapper for transaction isolation levels, called TransactionIsol......

writeademo
27分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部