文档章节

Spring源码解析(七)——实例创建(中)

MarvelCode
 MarvelCode
发布于 06/23 15:12
字数 2876
阅读 5
收藏 1
点赞 0
评论 0

前言

    上一节讲到了,Spring 会根据实例的作用域执行不同的创建逻辑,分别是 Singleton、Prototype、其他 Scope,其中 Singleton 会调用 getSingleton 从缓存中获取,缓存中没有才会创建实例;Prototype 每次都会创建;其他 Scope 会调用 Scope.get 获取,保证各作用域内实例唯一。

    它们的公共创建逻辑都是  createBean 方法。

 

源码解读

    createBean 方法由 AbstractAutowireCapableBeanFactory 实现。

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
        implements AutowireCapableBeanFactory {

    // bean默认实例化策略 —— Ciglib增强代理
    private InstantiationStrategy instantiationStrategy = 
                              new CglibSubclassingInstantiationStrategy();

    @Override
    protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) 
                       throws BeanCreationException {
        if (logger.isDebugEnabled()) {
            logger.debug("Creating instance of bean '" + beanName + "'");
        }
        RootBeanDefinition mbdToUse = mbd;

        // 解析获取 bean对应类的 Class对象,并拷贝一份 RootBeanDefinition
        Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
        if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
            mbdToUse = new RootBeanDefinition(mbd);
            mbdToUse.setBeanClass(resolvedClass);
        }

        /**
         * 对于 methodOverrides的校验,即 lookup-method和 replaced-method
         * 如果指定的方法不存在,会抛出异常
         */
        try {
            mbdToUse.prepareMethodOverrides();
        } catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
                    beanName, "Validation of method overrides failed", ex);
        }

        try {
            // 让 BeanPostProcessors有机会返回代理而不是目标 bean实例
            Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
            if (bean != null) {
                return bean;
            }
        } catch (Throwable ex) {
            throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
                    "BeanPostProcessor before instantiation of bean failed", ex);
        }

        // 创建目标 bean实例
        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        if (logger.isDebugEnabled()) {
            logger.debug("Finished creating instance of bean '" + beanName + "'");
        }
        return beanInstance;
    }
}

    首先会解析出要创建实例的类型,之后是对 methodOverrides 的校验

  • lookup-method :用于将 bean 的指定方法(name属性),配置指定返回哪些实例(bean属性);
  • replaced-method :用于将 bean 的指定方法(name属性),替换为——“实现MethodReplacer”的对象(replacer属性),即方法替换为实现的 reimplement 方法。

    这些替换的前提就是,被指定的方法一定要存在,这就是校验的目的。之后就有两条线了,一个是代理路线(resolveBeforeInstantiation),另一个是常规的实例创建路线(doCreateBean)。

 

resolveBeforeInstantiation

    protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
        Object bean = null;
        if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
            // 判断 bean是否为合成的(即不是应用本身定义的),例如 <aop-config>创建的
            // 判断全局是否注册有 InstantiationAwareBeanPostProcessor(BeanPostProcessor子类)
            if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
                // 获取 bean的目标类型
                Class<?> targetType = determineTargetType(beanName, mbd);
                if (targetType != null) {
                    // 调用 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation
                    bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                    // 返回不为 null的实现只有:AbstractAutoProxyCreator和 ScriptFactoryPostProcessor                  
                    if (bean != null) {
                        // 直接调用 BeanPostProcessor.postProcessAfterInitialization 
                        bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                    }
                }
            }
            // 设置是否被处理的标志位
            mbd.beforeInstantiationResolved = (bean != null);
        }
        return bean;
    }

    protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
        // 遍历 InstantiationAwareBeanPostProcessor
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
                // 只要有一个返回不为 null,就会返回
                if (result != null) {
                    return result;
                }
            }
        }
        // 遍历所有 InstantiationAwareBeanPostProcessor
        // 没有一个 postProcessBeforeInstantiation返回不为 null
        return null;
    }


    @Override
    public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException {
        Object result = existingBean;
        // 遍历 BeanPostProcessor
        for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
            result = beanProcessor.postProcessAfterInitialization(result, beanName);
            // 和 postProcessBeforeInstantiation相反
            // 只要有一个返回为 null,就会返回
            if (result == null) {
                return result;
            }
        }
        // 遍历所有 BeanPostProcessor
        // 没有一个 postProcessAfterInitialization返回为 null
        return result;
    }

    我们看到了 bean 生命周期相关接口的执行,分别是 postProcessBeforeInstantiation和 postProcessAfterInitialization。前者是在构造器调用前被执行,后者是属性填充后被调用,因为 AOP 代理并非常规的实例创建,少了类似属性填充等过程,所以自然少了与之关联的其他“生命周期”接口调用,在 postProcessBeforeInstantiation 调用后就直接调用 postProcessAfterInitialization 宣告初始化结束。让我们来看看 AOP 代理的逻辑:

public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
        implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {

    // 有自定义的 TargetSource直接创建代理对象
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        Object cacheKey = getCacheKey(beanClass, beanName);

        if (beanName == null || !this.targetSourcedBeans.contains(beanName)) {
            // 下面判断的缓存
            if (this.advisedBeans.containsKey(cacheKey)) {
                return null;
            }
            // 不代理的条件一:非 Advice、Pointcut、Advisor、AopInfrastructureBean子类
            // 不代理的条件二:shouldSkip返回 true,默认返回 false
            // - AspectJAwareAdvisorAutoProxyCreator:所有 AspectJPointcutAdvisor指定增强 bean应该跳过
            if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
                // 满足条件的不会进行代理处理
                this.advisedBeans.put(cacheKey, Boolean.FALSE);
                return null;
            }
        }

        // 如果我们有自定义的 TargetSource,就创建代理
        // TargetSource将以自定义的方式处理目标实例
        if (beanName != null) {
            // 由自定义的 TargetSourceCreator.getTargetSource返回,没有则返回 null
            TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
            if (targetSource != null) {
                // 这里会放入缓存,入口就无需再判断
                this.targetSourcedBeans.add(beanName);
                // 返回满足条件的 Advice或者 Advisor集合,涉及两个分支:
                // BeanNameAutoProxyCreator:给名字匹配 bean自动创建代理
                // AbstractAdvisorAutoProxyCreator:给容器中满足 Advisor中指定切点创建代理
                Object[] specificInterceptors =
                        getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
                // 创建代理
                Object proxy =
                        createProxy(beanClass, beanName, specificInterceptors, targetSource);
                this.proxyTypes.put(cacheKey, proxy.getClass());
                // 一旦返回,就不会再进行常规的实例创建了
                return proxy;
            }
        }

        return null;
    }

    protected Object createProxy(Class<?> beanClass, String beanName,
                                 Object[] specificInterceptors, TargetSource targetSource) {

        if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
            AutoProxyUtils.exposeTargetClass(
                    (ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
        }

        // 采用 ProxyFactory来进行代理创建
        ProxyFactory proxyFactory = new ProxyFactory();
        // 复制当前类的相关配置
        proxyFactory.copyFrom(this);

        if (!proxyFactory.isProxyTargetClass()) {
            // 检查 beanDifinition的是否设置 preserveTargetClass为 true
            if (shouldProxyTargetClass(beanClass, beanName)) {
                // 满足条件,使用 TargetClass代理
                // 如果 TargetClass为接口或代理类时,使用JDK代理,否则使用 Ciglib代理
                proxyFactory.setProxyTargetClass(true);
            } else {
                // 看是否有合理的接口,逻辑如下
                evaluateProxyInterfaces(beanClass, proxyFactory);
            }
        }
        // 整理合并Advisor:自定义切面和公共拦截(涉及到先后执行顺序)
        // 公共拦截:interceptorNames,Advice会被包装成 DefaultPointcutAdvisor
        Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
        // 添加切面
        proxyFactory.addAdvisors(advisors);
        proxyFactory.setTargetSource(targetSource);
        // 空实现
        customizeProxyFactory(proxyFactory);

        proxyFactory.setFrozen(this.freezeProxy);
        if (advisorsPreFiltered()) {
            proxyFactory.setPreFiltered(true);
        }
        // 返回代理对象
        return proxyFactory.getProxy(getProxyClassLoader());
    }

    protected void evaluateProxyInterfaces(Class<?> beanClass, ProxyFactory proxyFactory) {
        // 获取类实现的所有接口
        Class<?>[] targetInterfaces =
                ClassUtils.getAllInterfacesForClass(beanClass, getProxyClassLoader());
        boolean hasReasonableProxyInterface = false;
        // 遍历所有接口,找出合理的接口
        for (Class<?> ifc : targetInterfaces) {
            // 条件一:接口非 InitializingBean、DisposableBean、Closeable、AutoCloseable、父接口非 Aware
            // 条件二:接口非 groovy.lang.GroovyObject、cglib.proxy.Factory、bytebuddy.MockAccess
            // 条件三:接口方法至少一个
            if (!isConfigurationCallbackInterface(ifc) && !isInternalLanguageInterface(ifc) &&
                    ifc.getMethods().length > 0) {
                hasReasonableProxyInterface = true;
                break;
            }
        }
        if (hasReasonableProxyInterface) {
            for (Class<?> ifc : targetInterfaces) {
                proxyFactory.addInterface(ifc);
            }
        } else {
            // 没有合理的接口,使用 TargetClass代理
            proxyFactory.setProxyTargetClass(true);
        }
    }

}

    以上是有自定义 TargetSource 自动代理的创建过程,如果没有自定义 TargetSource,就需要在常规实例创建过程中(见下节 initializeBean),走到 postProcessAfterInitialization 来进行代理创建:

public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
        implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName)
            throws BeansException {
        if (bean != null) {
            Object cacheKey = getCacheKey(bean.getClass(), beanName);
            if (!this.earlyProxyReferences.contains(cacheKey)) {
                return wrapIfNecessary(bean, beanName, cacheKey);
            }
        }
        return bean;
    }

    protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        // 这里缓存逻辑同 postProcessBeforeInstantiation
        if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
            return bean;
        }
        if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
            return bean;
        }
        if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return bean;
        }

        // 同样获取满足条件的 Advice或者 Advisor集合
        Object[] specificInterceptors =
                getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
        if (specificInterceptors != DO_NOT_PROXY) {
            this.advisedBeans.put(cacheKey, Boolean.TRUE);
            // 同样调用 createProxy创建代理
            Object proxy = createProxy(
                    bean.getClass(), beanName, specificInterceptors,
                    new SingletonTargetSource(bean));
            this.proxyTypes.put(cacheKey, proxy.getClass());
            return proxy;
        }

        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }

}

 

doCreateBean

    接下来就是常规实例的创建概览了。

    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
            throws BeanCreationException {

        BeanWrapper instanceWrapper = null;
        // 如果是单例,首先要取出未完成的FactoryBean实例的缓存
        if (mbd.isSingleton()) {
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        // 如果没有缓存,根据指定 bean使用对应策略创建新实例,将 BeanDefinition转化为 BeanWrapper
        if (instanceWrapper == null) {
            // 会调用构造器来实例化对象,展开此方法
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
        Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
        mbd.resolvedTargetType = beanType;

        // 后处理器修改合并的 bean定义.
        // 锁对象,防并发
        synchronized (mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                    // 生命周期:MergedDefinitionPostProcessors.postProcessMergedBeanDefinition
                    applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                } catch (Throwable ex) {
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                            "Post-processing of merged bean definition failed", ex);
                }
                // 置标志位,确保仅执行一次
                mbd.postProcessed = true;
            }
        }

        // 是否需要提早曝光:可以解决单例间循环引用依赖
        // 条件:单例 & 允许循环依赖 & 当前bean在创建中,检测循环依赖
        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");
            }
            /**
             * 为避免后期循环依赖,在bean初始化完成前将创建实例的 ObjectFactory放入工厂
             * 循环依赖时仅通过 ObjectFactory创建实例即可
             */
            addSingletonFactory(beanName, new ObjectFactory<Object>() {
                @Override
                public Object getObject() throws BeansException {
                    /**
                     * 生命周期:SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference
                     * Aop就是在此将 advice动态植入 bean,如果没有则直接返回 bean
                     */
                    return getEarlyBeanReference(beanName, mbd, bean);
                }
            });
        }

        Object exposedObject = bean;
        try {
            /**
             * 生命周期:InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation
             * 自动装配(区分 byName、byType)
             * 生命周期:InstantiationAwareBeanPostProcessor.postProcessPropertyValues
             * 属性填充
             */
            populateBean(beanName, mbd, instanceWrapper);
            if (exposedObject != null) {
                /**
                 * BeanNameAware、BeanClassLoaderAware、BeanFactoryAware
                 * 生命周期:BeanPostProcessor.postProcessBeforeInitialization
                 * 生命周期:InitializingBean.afterPropertiesSet
                 * 生命周期:调用初始化方法:init-method
                 * 生命周期:BeanPostProcessor的postProcessAfterInitialization
                 */
                exposedObject = initializeBean(beanName, exposedObject, mbd);
            }
        }......// 省略 catch

        /**
         * 提前曝光处理:父类 DefaultSingletonBeanRegistry持有 earlySingletonObjects
         * 存储了在创建 bean早期对创建的原始 bean的一个引用
         * getSingleton会查询 earlySingletonObjects时候包含了 beanName
         * 因此如果返回不为空说明检测到了循环依赖
         */
        if (earlySingletonExposure) {
            Object earlySingletonReference = getSingleton(beanName, false);
            if (earlySingletonReference != null) {
                if (exposedObject == bean) {
                    exposedObject = earlySingletonReference;
                }
                // hasDependentBean:判断 dependentBeanMap是否包含该 beanName
                // 见:创建实例(上),doGetBean处理 depends-on,registerDependentBean
                else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                    // 返回依赖于指定 beanName的所有 beanName
                    String[] dependentBeans = getDependentBeans(beanName);
                    Set<String> actualDependentBeans =
                            new LinkedHashSet<String>(dependentBeans.length);
                    for (String dependentBean : dependentBeans) {
                        // alreadyCreated不包含 dependentBean会返回 false
                        // 即 dependentBean依赖的 bean已被创建,但它自身还没完成创建
                        if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                            actualDependentBeans.add(dependentBean);
                        }
                    }
                    // 上面扫描后发现还有依赖 bean未创建完成的会抛出异常
                    if (!actualDependentBeans.isEmpty()) {
                        throw new BeanCurrentlyInCreationException(...// 省略异常信息)
                    }
                }
            }
        }

        // 根据作用域注册bean(这里的bean仅是未进行属性填充的bean)
        try {
            registerDisposableBeanIfNecessary(beanName, bean, mbd);
        } catch (BeanDefinitionValidationException ex) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
        }

        return exposedObject;
    }

    这一步可以说涵盖了常规实例创建的全过程——实例化Instantiation)和初始化Initialization) ,实例化可以笼统认为是 new 一个对象,初始化可以理解为在实例化的基础上,进行各个成员属性的填充。这一节我们将实例化展开讲解,下一节再对初始化讲解。

 

createBeanInstance

    protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
        // 解析出目标 bean的 Class对象
        Class<?> beanClass = resolveBeanClass(mbd, beanName);

        // isNonPublicAccessAllowed默认返回 true,即非 public的类同样可以实例化
        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());
        }

        // 如果配置了 factory-method,使用工厂方法实例化
        // 见 ConstructorResolver.instantiateUsingFactoryMethod
        if (mbd.getFactoryMethodName() != null) {
            return instantiateUsingFactoryMethod(beanName, mbd, args);
        }

        boolean resolved = false;
        boolean autowireNecessary = false;
        // 没有指定构造器参数,需要解析使用哪个构造器
        if (args == null) {
            synchronized (mbd.constructorArgumentLock) {
                // 不为空说明解析过,避免下面重复解析
                if (mbd.resolvedConstructorOrFactoryMethod != null) {
                    resolved = true;
                    autowireNecessary = mbd.constructorArgumentsResolved;
                }
            }
        }
        /**
         * 解析过直接从 RootBeanDefinition中属性 resolvedConstructorOrFactoryMethod中取
         * 首次解析后会更新 resolvedConstructorOrFactoryMethod属性(包含工厂方法、构造器注入、默认构造器)
         */
        if (resolved) {
            if (autowireNecessary) {
                // 构造器自动注入
                // 见 ConstructorResolver.autowireConstructor
                return autowireConstructor(beanName, mbd, null, null);
            } else {
                // 使用默认构造器构造(即无参构造器)
                // 见 SimpleInstantiationStrategy.instantiate
                return instantiateBean(beanName, mbd);
            }
        }

        // 首次解析的过程
        // 判断使用哪个构造器:如果实现了 SmartInstantiationAwareBeanPostProcessor,可以通过方法 determineCandidateConstructors指定,否则返回 null
        Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
        if (ctors != null ||
                mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
                mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
            // 构造函数自动注入
            / 见 ConstructorResolver.autowireConstructor
            return autowireConstructor(beanName, mbd, ctors, args);
        }

        // 使用默认构造器(即无参构造器)
        // 见 SimpleInstantiationStrategy.instantiate
        return instantiateBean(beanName, mbd);
    }

    实例化分为三种方式:工厂方法构造器注入、以及默认构造器。具体处理代码集中于 ConstructorResolver SimpleInstantiationStrategy,为了保证整个创建流程的清晰,这里不展开讲解,有兴趣的可以自行研究下。

    经过这一步的处理,bean就已经被实例化了,包装在 BeanWrapper 中,通过调用 getWrappedInstance 就可以获取。

 

总结

    到目前为止创建实例的进度来看,可以简单的理解为,我们已经完成了 new 一个对象的操作,但还未调用 setter 方法为成员变量赋值,这将留到下一节“初始化”进行展开分析。

© 著作权归作者所有

共有 人打赏支持
MarvelCode
粉丝 40
博文 27
码字总数 53412
作品 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
SpringCloud Eureka 源码解析 —— 应用实例注册发现(六)之全量获取

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

Harries Blog™
2017/12/31
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
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
spring boot 1.5.4 入门和原理(二)

1 spring boot入门 1.1 环境准备 JDK 7及以上 eclipse开发工具 项目管理工具Maven 本文采用、RELEASE(或1.5.2.RELEASE)调试通过。 spring-boot相关项目源码, 码云地址:https://git.oschi...

wyait
2017/09/18
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

回想过往,分析当下,着眼未来

好久没有真正的在纸质笔记本上写过东西了,感觉都快不会写字了,笔画都不知道怎么写了。接下来就说说咱们的正事。 2018年7月22日,我做了一个决定,那就是去参加安全培训(可能是我职业生涯中...

yeahlife
22分钟前
1
0
关于工作中的人际交往

关于工作中的人际交往 Intro 写了篇发泄情绪的博客,但不会发布出来。 大概就是,要么忍,要么滚。 以及一些不那么符合社会主义核心价值观,不满于大资本家与小资本家剥削的废话。

uniqptr
27分钟前
0
0
springMVC的流程

1.用户发送请求至前端控制器DispatcherServlet 2.DispatcherServlet收到请求调用HandlerMapping处理器映射器。 3.处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(...

JavaSon712
42分钟前
0
0
大数据教程(3.2):Linux系统软件安装之自动化脚本

博主前面文章有介绍过软件的安装,可以帮助IT人员顺利的完成功能软件安装;但是,对于我们运维人员或者需要管理软件安装的项目经理来说,有些应用一次行需要搭建很多台相同的软件环境(如tom...

em_aaron
今天
0
0
Spring Boot 2.0.3 JDBC整合Oracle 12

整合步骤 1. Oracle驱动引入 Oracle驱动一般不能通过maven仓库直接下载得到,需自行下载并导入到项目的lib目录下,建议通过如下pom依赖引入下载的Oracle驱动 <!-- Oracle 驱动 -->...

OSC_fly
今天
0
0
java 8 并行流 - 1

下面创建一个并行流,与顺序流 //顺序流Stream.iterate(0L, i -> i + 1) .limit(Integer.MAX_VALUE) .reduce(0L, Long::sum);//并行流Stream.iterate(0L, i -> i......

Canaan_
今天
0
0
数据结构与算法5

二分法采用向下取整的方法 使用有序数组的好处是查找的速度比无序数组快的多,不好的方面是因为要将所有靠后的数据移开,所以速度较慢,有序数组和无序数组的删除操作都很慢。 有序数组在查找...

沉迷于编程的小菜菜
昨天
1
1
SpringBoot | 第十一章:Redis的集成和简单使用

前言 上几节讲了利用Mybatis-Plus这个第三方的ORM框架进行数据库访问,在实际工作中,在存储一些非结构化或者缓存一些临时数据及热点数据时,一般上都会用上mongodb和redis进行这方面的需求。...

oKong
昨天
5
0
对基于深度神经网络的Auto Encoder用于异常检测的一些思考

一、前言 现实中,大部分数据都是无标签的,人和动物多数情况下都是通过无监督学习获取概念,故而无监督学习拥有广阔的业务场景。举几个场景:网络流量是正常流量还是攻击流量、视频中的人的...

冷血狂魔
昨天
0
0
并发设计之A系统调用B系统

A-->B A在发送请求之前,用乐观锁,减少对B的重复调用,这样一定程度上是幂等性。 比如A系统支付功能,要调用B系统进行支付操作,但是前端对"支付"按钮不进行控制,即用户会不断多次点击支付...

汉斯-冯-拉特
昨天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部