Spring IOC 概述

IOC(Inversion of Control) 控制反转,也叫 DI(D_ependency injection_) 依赖注入。是一种设计思想。不过我并不同意所谓反转的说法,因为没有谁规定什么方式就是“标准”的,如果我把IOC作为“标准”,IOC就是“标准”自身,何来反转?不过我行文也是沿用官方的说法,使用IOC描述这个技术

IOC其实是一种组装的思想,最简单理解 IOC 的方法,就是我们的组装电脑

  1. 主板,硬盘,显卡,CPU厂商们先定义好一个个插口。

  2. 然后主板厂商就在他的主板上面预留位置。比如 A 插口是 留给硬盘的,B插口是留给 CPU的。注意,主板生产完成时,硬盘和CPU并没有在主板上,而是空的,不过主板已经写好好了给 CPU 和 硬盘 供电的 功能。

  3. 我们的工作就是根据主板的插口来找件,装配,而不是先买CPU、内存、硬盘再去选主板,这就是IOC ,主板需要插什么接口的,我们就去获得相关的零件,这样整个电脑就可以工作。

首先,我们必须要知道,没有 Spring ,我们照样可以做所谓的 IOC,就是 主物预留插口 -> 按插口找件,组装。其实这在我们生活中随处可见。

那么,我们为什么要使用 Spring 呢,我们组装电脑,就要获得关于这个电脑的所有部件,比如主板、电源、内存等等,我们自己当然不可能凭空造出来,但是我们可以上商城购买,我们只需要关心接口对不对,而不用关心他是怎么生产的。那么,Spring 的角色就是一个商城。

我们可以把 Spring IOC 看成一个全产业链的商城,他会把产业链中的第一层原料开始,每一层都登记进入商城。在这个商城里面,我们可以买到任何层级的零件。之后,我们就可以自由的控制一切:如果我们是厂商,我们可以买到我们想要的零件。如果我们是消费者,想组装电脑,就可以买到主板,硬盘和CPU。如果我们有了机房,就可以直接买到若干个电脑。甚至,我们有一个国家,就可以在上面买到关于这个国家的一切。我们再不用关心东西是怎么来的,我们只管买即可。东西生产由其他人负责。而Spring IOC做的就是整个产业链从头到尾的组装,上架工作。

Spring IOC的好处也是众说纷纭,我也没有找到很有说服力的解释,姑且写一些在下面:

  1. 轻松实现面向接口编程,中心管理,按需取用,各个环节完全解耦,比如,网站环境和测试环境差异巨大,也可以轻松切换。

  2. 可以监听和控制所管理对象的生命周期,并且执行相关的操作

  3. 因为可以控制对象的生命周期,所以可以轻松通过 AOP 进行对象增强

  4. 轻松整合整个 Java 生态链,对于开发者来说,整合是轻松友好的。

Spring IOC 用法解析

随着 SpringBoot 的潮流, 我们坚持只使用注解配置 Spring IOC

SpringIOC使用例子

maven 配置依赖

12345
<dependency>  <groupId>org.springframework</groupId>  <artifactId>spring-context</artifactId>  <version>4.3.11.RELEASE</version></dependency>

spring-context 会自动将 spring-core、spring-beans、spring-aop、spring-expression 这几个基础 jar 包带进来。

定义一个接口 (类比的话,就是主物上面的一个接口)

123
public interface MessageService { String getMessage();}

定义接口实现类(类比的话,就是零件自身),并且使用注解注册到 Spring 商城

1234567
@Component("messageService")public class MessageServiceImpl implements MessageService {

 public String getMessage() { return "hello world"; }}

使用: (类比的话,就是从商城买东西) (这里没有使用依赖注入(自动装配),下面会介绍)

12345678910
// Main.java@ComponentScan // 非常重要,会扫描包下所有注解public class Main { public static void main(String[] args) { ApplicationContext context = new AnnotationConfigApplicationContext(Main.class); MessageService messageService = (MessageService) context.getBean("messageService"); System.out.println(messageService.getMessage()); // 输出 Hello, World }}

SpringIOC 登记方式

Spring中管理的对象都叫 Bean,就像商城里面的一种商品。Spring 管理的对象默认是单例的,也就是一种商品只有一件,不过可以重复购买(注入)。下面,我们说一下如何上架这些商品。

普通类的对象登记

  • @Component 通用的登记方式,以下的注解都包含这个注解的功能,并且可能有额外的含义

  • @Service 通常用于服务层

  • @Controller 通常用于控制层

  • @Repository 通常用于数据库仓库层

  • 后面加(“”) 定义 bean 的名字,也可以不定义自动由 Spring 生成。

例子:

1234567
@Component("messageService")public class MessageServiceImpl implements MessageService {

 public String getMessage() { return "hello world"; }}

工厂创建的对象登记

我们有时候想通过一个工厂的方式,根据传入不同对象,生成不同的对象,并登记到 Spring,我们要这么做

1234567891011121314
@Configurationpublic class DataConfig{  @Bean("aSource") // 配置文件来源,通常用 properties 文件定义 public DataSource source(){ DataSource source = new RedisProperties(); source.setHost("localhost"); source.setPassword("123"); return source; } @Bean(name = "redisTemplate")  public RedisTemplate redisTemplate(@Qualifier("aSource") DataSource source) { return super.stringRedisTemplate(source);  }}

我们现在就注册到了一个 redisTemplate 的 Bean,是通过我们的配置文件生产的。
其中有这些注解

  • @Configuration 说明这是个配置类

  • @Bean 说明这个函数是用来创建 Bean 的

  • @Qualifier 说明我们引入哪一个 Bean 作为 传入参数。

  • 我们可以写多组这样的函数,就会创造出不同的 Bean

另外还有可能用到的是 @Lazy ,可以让 bean 在用的时候再加载。

SpringIOC 注入方式

当然,除了上面的 getBean 外,Spring还给我们封装了许多方法方便我们买东西:
其中,@Autowired 注解 最常用,意思是按类型装配,如果这个类型的零件只有一个,那么就默认选这一个。如果是有多个,那么还需要我们指定具体是哪一个。

setter

12345678
@Componentpublic class Customer {  private Person person; @Autowired  public void setPerson (Person person) { this.person=person; }}

filed

123456
@Componentpublic class Customer { @Autowired  private Person person;  private int type;}

构造函数

12345678
@Componentpublic class Customer { private Person person; @Autowired // 甚至可以直接不写 public Customer (Person person) {  this.person=person; }}

如果一个类型对应多个 Bean,使用 @Qualifier 指定

123456789101112131415
@Componentpublic class BeanB1 implements BeanInterface { //}@Componentpublic class BeanB2 implements BeanInterface { //}@Componentpublic class BeanA { @Autowired @Qualifier("beanB2") private BeanInterface dependency; ...}

Spring IOC 生命周期与扩展点

Spring IOC生命周期:

  1. 初始化 BeanFactory

    1. 创建 BeanFactory

    2. 读取 BeanDefinition

  2. 通过BeanDefinition,初始化 Bean

  3. 供外部调用

  4. BeanFactory销毁

我们可以在 Spring IOC 的生命周期中置入各种我们自定义的逻辑。

  1. 单独类实现接口,一般是应用于全局的

  2. Bean 继承 Aware 类,一般是用于该 Bean 获取环境变量

  3. Bean 实现 接口,一般是用于该 Bean

  4. Bean 上 注解,一般是用于该 Bean

初始化 BeanFactory 之后

实现 BeanFactoryPostProcessor 在BeanFactory初始化之后(已经读取了配置但还没初始化Bean),做一些操作,可以读取并修改BeanDefinition

1234567
@Componentpublic class LifeCycleControl implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { //.. doSomeThing }}

初始化 Bean 时

顺序如下:

  • 开始几步分别是:实例化、构造函数、设置属性函数,并且,在这里,其实Spring早就已经把所有属性都注入好了,下面的过程都是 Spring 预留给用户扩展的。

  • BeanNameAware抽象类 可以 获取到 BeanName,其他几个 Aware 类似

1234567
@Componentpublic class TestB extends BeanNameAware { @Override public void setBeanName(String name) { // 会告诉 TestB 他的 BeanName 是什么 }}
  • BeanPostProcessor接口 对每一个 Bean 初始化前后进行置入,有多少个 Bean 就会执行多少次

    1. postProcessBeforeInitialization(Object bean, String beanName)

    2. postProcessAfterInitialization(Object bean, String beanName)

  • @PostConstruct 注解(在Bean上),用户自定义的该Bean的初始化操作

  • InitializingBean接口的afterPropertiesSet()方法会被调用

  • init-method 用注解的话,这个一般不用了,一定要用的话,可以用 @Bean(initMethod = “initMethodName”),在配置中心配置,不能在 Bean 上配置。

Spring IOC 构成

Bean

Bean 是 Spring 里面最基本的单位,如果把 Spring 管理的对象看成一群人,那么 Bean 就是每一个人。
在用户看来,bean 就是一个实际的对象,比如

1
MessageService messageService = context.getBean(MessageService.class);

在Spring内部,Bean的本质是一个 BeanName -> BeanDefinition 的键值对 ,即用于搜索的名字,和他的实际定义内容。
比如:

1
<bean id="messageService" class="ma.luan.example.MessageServiceImpl"/>

就定义了一个 Bean,Name 是 messageService ,BeanDefinition 的内容之一是 ma.luan.example.MessageServiceImpl

ApplicationContext:

Spring IOC 的门面,供用户调用,起到统筹全局的作用。背后它从源(Resource)读取配置 ,为每个 bean 生成配置对象(BeanDefinition) 到工厂(BeanFactory)的注册中心(Registry) ,控制工厂管理 Bean (Autowire),代理工厂的 getBean 操作。我们可以使用多种输入方式 Context。

BeanFactory

Spring 的核心,他管理着一个注册中心 Registry,并且负责管理 Bean(加载类,实例化,注入属性等),并且提供 getBean 等操作

  • BeanFactory: 可以获取一个 Bean 的能力的接口,有getBean方法

  • ListableBeanFactory,有一次获取多个 Bean 能力的接口,有getBeans方法

  • HierarchicalBeanFactory,有继承能力的工厂接口,有一个 getParentBeanFactory 方法,可以获取父工厂,先不用管

  • AutowireCapableBeanFactory 可以自动装配的工厂接口,继承它让我们的工厂可以对 Bean 自动创建,属性进行自动插入的能力。autowireBean、createBean、initializeBean、applyBeanPostProcessorsBeforeInitialization 等等,是工厂最核心的能力

  • DefaultListableBeanFactory,继承了所有接口,是我们最常使用的标准工厂。他继承并实现了所有的能力

    1. getBean

    2. getBeans

    3. getParentBeanFactory

    4. AutowireCapable

    5. Config (修改设置)

  • ApplicationContext虽然也继承了 BeanFactory,但是实际上是复用了他的 getBean() 等接口,实际逻辑代码并没有什么继承关系

BeanRegistry

注册中心,维护着多个 Map,用于登记 Bean 的信息,包括 BeanDefinition 的 Map,还有 存放单例的 singletonObjects 的 Map 等等。

BeanDefinition

BeanDefinition存放我们在配置文件中对某个 Bean 的所有注册信息,和存放该对象的实际单例对象。
比如,
我们在 xml 文件中配置

1
<bean id="messageService" class="ma.luan.example.MessageServiceImpl"/>

那么, BeanRegistry 中 会有
messageService -> BeanDefinition
BeanDefinition里面有关于这个 Bean 的所有配置

ResourceLoader

负责从多个配置源(Resource)读取配置文件,源包括 XML、注解等等,XML有可能来自本地或者网络。

DefinitionReader

从 ResourceLoader 加载到配置资源后,把配置转成(read) Definition 的形式

启动过程分析

简单起见,我们可能还是要用回 XML 配置启动的方法(ClassPathXmlApplicationContext)来分析 (真香),不过其实内部大同小异。

123456
public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("classpath:application.xml"); MessageService messageService = context.getBean(MessageService.class); System.out.println(messageService.getMessage()); // 输出 hello world}

ClassPathXmlApplicationContext 构造方法

123456789
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {

 super(parent);  setConfigLocations(configLocations); // 保存XML路径 if (refresh) { refresh(); // 第一次执行会到这里,初始化  }}

核心启动器:refresh 方法

refresh方法是启动的核心方法,执行了启动的所有操作,后面还会提到余下的部分

123456789101112
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // 准备工作,记录下容器的启动时间、标记“已启动”状态、处理配置文件中的占位符 prepareRefresh();

 // 创建工厂,读取 XML,把 BeanName -> BeanDefinition 在 BeanFactory 的 Registry 里 注册 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

  // ....

 }}

创建工厂并在 Context 中保存引用

obtainFreshBeanFactory 方法

这个方法干了下面几件事

  1. 创建了 beanFactory (DefaultListableBeanFactory),并且把 beanFactory 赋值给 Context 保存

  2. 读取 Context 的配置,设置该工厂 是否允许 Bean 覆盖、是否允许循环引用 等

  3. Context 读取加载 BeanDefinition,把 BeanDefinition 注册到 BeanFactory 的 Map 中

    1. 配置 DefinitionReader,读取 Resource

    2. 从XML读取配置树,转换成 Definition,触发监听事件

创建好之后的 beanFactory 的一部分的截图

创建工厂后的维护操作

主要是在 BeanFactory 里面注册实现了各种接口的Bean,Factory会为每一个特殊的接口类型维护一个列表,以后到达特定的位置,就会遍历这个列表。
比如 实现了 BeanPostProcessors 的接口的 Bean 有 A,B,C,那么到时候初始化 Bean 之前,就会遍历调用A,B,C的 postProcessBeforeInitialization方法,初始化 Bean 之后,就会调用 A,B,C 的postProcessAfterInitialization 方法,具体什么时候调用什么方法,请查看后面写的 Spring Bean 生命周期

1234567891011121314151617181920212223242526272829303132333435
@Overridepublic void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {

 prepareRefresh();

 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

 // 主要是设置 BeanFactory 的 ClassLoader prepareBeanFactory(beanFactory);

 try { // 注册实现了 BeanFactory 的 Bean postProcessBeanFactory(beanFactory); // 调用上面注册的 Bean 的相关方法 (用于 BeanFactory 读取 Definition 之后,初始化之前) invokeBeanFactoryPostProcessors(beanFactory); // 这个比较会用到,检测 注册好的 Bean 里面,实现了 BeanPostProcessors 接口的 Bean // 等下初始化 Bean 的前后,会调用这些所有 Bean 的 相关方法 registerBeanPostProcessors(beanFactory); // 国际化的,用不到 initMessageSource(); // 注册ApplicationEvent接口的Bean,初始化事件广播器 initApplicationEventMulticaster(); // 给子类的钩子,会再注册一些内置 Bean onRefresh(); // 注册实现了 ApplicationListener 接口的 Bean registerListeners();

 // 初始化所有的 singleton beans (lazy-init 的除外):下面讲 finishBeanFactoryInitialization(beanFactory);

 // ... } //... }

初始化 Bean

Spring 默认 初始化的 Bean对象 都是单例的,采用的是单例注册表的方法。
我们重点关注单例如何实现,怎么解决循环引用

首先,初始化入口在 finishBeanFactoryInitialization(beanFactory),就是在 refresh() 方法的尾部。这个方法会进行马上初始化的 bean 进行马上初始化。

因为要兼容 延迟初始化(getBean时候加载) 和 马上初始化,所以最合适的方式就是把加载的逻辑写在 getBean 里边,需要马上加载的时候,提前调用 getBean 即可。

finishBeanFactoryInitialization

核心方法是 preInstantiateSinletons():
对符合条件的所有 beandefinition 里面 的 bean 执行了初始化操作:

12345678910111213141516171819202122
public void preInstantiateSingletons() throws BeansException { // this.beanDefinitionNames 保存了所有的 beanNames List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);

 // 触发所有的非懒加载的 singleton beans 的初始化操作 for (String beanName : beanNames) {

 // 非抽象、非懒加载的 singletons。如果配置了 'abstract = true',那是不需要初始化的 if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {

 if (isFactoryBean(beanName)) { // FactoryBean 的话,在 beanName 前面加上 ‘&’ 符号。再调用 getBean final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName); } else { // 对于普通的 Bean,只要调用 getBean(beanName) 这个方法就可以进行初始化了 getBean(beanName); } } }

 }

getBean

我去掉了部分无关紧要的代码,如果有兴趣可以去看原文件 AbstractBeanFactory

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

@SuppressWarnings("unchecked")protected <T> T doGetBean( final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException { // 获取 BeanName final String beanName = transformedBeanName(name);

 // 这个是返回值 Object bean;

 // 检查单例是否已经初始化,单例全部注册在 regisrty 的 singletonObjects,多例不会在这里注册 Object sharedInstance = getSingleton(beanName); // 如果注册表中没有这个单例,会返回 null,后面还会讲到这个方法

 // 开始创建 bean if (sharedInstance != null) { bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); // 默认非 BeanFactor 时,等同于 bean = sharedInstance } else { // 如果上面为 null,则说明单例未初始化,或者是多例

 final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); // 这里,实际执行了:this.beanDefinitionMap.get(beanName) // 就是把 BeanDefinition 拿出来了

 // 这里有一百多行代码,除了插入各种钩子和特殊情况,其实我们只执行了一行代码 bean = createBean(beanName, mbd, args) } return (T) bean; }

所以,getBean 就是 配套钩子 + 执行 createBean 方法
创建好的对象会放在 单例注册表 singletonObjects 中,下次再取的时候就从表里取,而不重新创建,从而实现单例模式。

createBean方法

如果单例还未创建,会在此创建 Bean
createBean 方法 主要做了些前置的工作,包括给 AOP 预留的拦截器 (AOP时,返回 Proxy 对象而不是真正的对象)
然后委托给 doCreateBean 方法,主要做了下面这些事:

  1. 实例化对象

  2. 装配属性

  3. 执行 InitializingBean 接口,BeanPostProcessor 接口钩子, init 方法钩子 (生命周期钩子)

我们主要关心一下怎么解决循环引用的问题:

123456789
<bean id="circleA" class="entity.CircleA" > <property name="circleB" ref="circleB"/></bean><bean id="circleB" class="entity.CircleB" > <property name="circleC" ref="circleC"/></bean><bean id="circleC" class="entity.CircleC" > <property name="circleA" ref="circleA"/></bean>

这样就构成了一个循环依赖,而我们默认是单例的,那如何一次性创建三个对象呢?
首先,在实例化对象的时候,先在 singletonFactories 注册一个工厂

1234567
addSingletonFactory(beanName, new ObjectFactory<Object>() {   @Override   public Object getObject() throws BeansException { return getEarlyBeanReference(beanName, mbd, bean); }});// this.singletonFactories.put(beanName, singletonFactory);

circleA 属性注入时,到了 circleB ,会 getBean(circleB) ,然后又会 getBean(circleC)
getBean(circleC) 时,又看到了A ,会调用回 getBean(circleA),在getBean的时候,会调用getSingleton,他会先从工厂取,这个时候A已经在工厂列表了,然后用getObject,就可以拿到A的引用。

123456789101112131415161718192021
protected Object getSingleton(String beanName, boolean allowEarlyReference) { Object singletonObject = this.singletonObjects.get(beanName); // getBean 默认走这里,从单例注册表拿已经创建好的单例,但是现在A还没创建好 if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { // 单例注册表里面没有,对象正在初始化,符合循环引用的条件 synchronized (this.singletonObjects) { singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) { ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { singletonObject = singletonFactory.getObject(); // getObject,就是把A的引用拉过来了,A其实还没建好,不过他的引用已经有了 this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } // 返回A的引用给C return (singletonObject != NULL_OBJECT ? singletonObject : null); }

这样就可以解决循环引用的问题

拾遗

Spring中的监听器用法

123456789101112131415161718192021222324252627282930313233
// 自定义事件public class MyEvent extends ApplicationEvent { public MyEvent(Object source) { super(source); }}// 自定义 Bean 实现 ApplicationContextAware 接口@Componentpublic class HelloBean implements ApplicationContextAware { private ApplicationContext applicationContext; private String name; public void setApplicationContext(ApplicationContext context) { this.applicationContext = context; } // 当调用 setName 时, 触发事件 public void setName(String name) { this.name = name; applicationContext.publishEvent(new MyEvent(this)); // 这行代码执行完会立即被监听到 } public String getName() { return name; }}// 自定义监听器, 监听上面的事件@Componentpublic class MyApplicationListener implements ApplicationListener { @Override public void onApplicationEvent(ApplicationEvent event) { if (event instanceof MyEvent) { System.out.println(((HelloBean)event.getSource()).getName()); } }}

Spring IOC中的主要设计模式

  1. 单例模式

  2. 观察者模式 (Listener)

参考资料

Spring IOC 容器源码分析
Tiny-spring: A tiny IoC container refer to Spring.
Spring4参考手册中文版
Spring Framework Reference Documentation
Spring的扩展点
Spring Bean Life Cycle Tutorial

转载于:https://www.cnblogs.com/endv/p/11257617.html

Spring IOC 概述相关推荐

  1. Spring(2)——Spring IoC 详解

    Spring IoC 概述 IoC:Inverse of Control(控制反转) 读作"反转控制",更好理解,不是什么技术,而是一种设计思想,就是将原本在程序中手动创建对象的控 ...

  2. Spring IOC 组件概述

    IOC 概述 IOC: Inversion of Control(控制反转), 这里其实指的是: 将程序中需要使用的 POJOs, 丢入到容器中, 解析成统一的 BeanDefinition(主要基于 ...

  3. Spring IOC(一):概述

    参考书籍:<Spring技术内幕> 系列文章 Spring IOC(一):概述 Spring IOC(二):初始化 Spring IOC(三):依赖注入 Spring IOC(四):相关特 ...

  4. Spring IOC和DI概述

    一.IOC和DI 1. IOC (Inversionof Control): 其思想是反转资源获取的方向.传统的资源查找方式要求组件向容器发起资源查找请求.作为回应,容器适时的返回资源. 而应用了IO ...

  5. 1、spring的概述

    1.spring的概述 spring是什么     spring的两大核心     spring的发展历程和优势     spring体系结构 spring是什么 Spring 是分层的 Java S ...

  6. Spring IoC(二)IoC容器的初始化过程

    (一)IoC 容器初始化过程概述 1.1简要概述初始化过程 IoC 容器的初始化过程是通过refresh() 方法来启动的,这个方法标识着IoC 容器正式启动.具体来说,这个启动过程包括:BeanDe ...

  7. Spring IoC(一)IoC容器的设计与实现:BeanFactory与ApplicationContext

    在写BeanFactory与ApplicationContext 之前,我想先简单聊一聊Spring IoC 容器,希望能给大家一个参考.如果你对这反面的知识比较了解,可以直接跳过. (一)Sprin ...

  8. spring ioc原理解析

    概述 Spring IOC控制反转,分为两个方面解释: 控制:对象对于内部成员的控制 反转:将之前对象管理自己内部成员,转变为ioc容器管理,目的是接耦 IOC的好处是: 无需手动创建,拿来就用 享受 ...

  9. [Spring5]Spring框架概述

    Spring框架概述 1.Spring是轻量级的开源的JavaEE框架 2.Spring可以解决企业应用开发的复杂性 3.Spring有两个核心部分:IOC和Aop a.IOC:控制反转,把创建对象过 ...

  10. java 从一个容器获取对象,如何从 Spring IoC 容器中获取对象?

    前面几篇文章主要分析了 Spring IoC 容器如何初始化,以及解析和注册我们定义的 bean 信息. 其中,「Spring 中的 IoC 容器」对 Spring 中的容器做了一个概述,「Sprin ...

最新文章

  1. MIIC:互联网会成基础设施,智能硬件就是互联网硬件
  2. 读取siftgeo格式文件的matlab程序
  3. python中uss的用法_使用不同内存ussag管理Python多进程进程进程
  4. Linux报错./configure: error: C compiler cc is not found
  5. vue el-upload上传组件限制文件类型:accept属性
  6. 华为服务器停止响应,windows服务器停止工作
  7. 处理Excel,填充空白区域
  8. java中的gridy_JAVA格局管教器.
  9. 3d打印机 开源资料_3D打印的人类双手,开源课程资料以及更多新闻
  10. Ubuntu: apt安装clang
  11. 微信小程序使用组件实现移动端软键盘
  12. pdf照片显示正常打印时被翻转_2020年广东二级建造师准考证打印常见问题
  13. MoSE论文中Sequential Synthetic Dataset生成代码(时间序列多任务学习数据集)
  14. 智力过河游戏c语言,Flash AS代码实现智力过河小游戏
  15. 计算机毕业设计Java校园闲置物品交换平台系统(源码+系统+mysql数据库+lw文档
  16. alibaba的druid连接池的监控的两种方法
  17. python开发和大数据开发工程师_大数据开发工程师的岗位职责
  18. 算法学习之- 动态规划
  19. 【XSS漏洞06】神器beEF的安装与简介
  20. 全志A33移植ubuntu系统记录(1)V1.0(分色排版)

热门文章

  1. HTTP请求报头中各个字段的含义
  2. Centos 7 学习加入用户
  3. iOSpush过后返回多级界面
  4. Postdoctoral Position
  5. 50个常用的sql语句
  6. 你必须知道iPad的10件事
  7. 国庆期间新闻回顾:微软智斗盗版 华为出手3Com
  8. ***服务现状的理解
  9. DAC+DMA+TIM实现音频播放问题记录
  10. Qt5学习笔记之bin文件合成工具二:bin文件的读取和写入