参考:
https://www.jianshu.com/p/1dec08d290c1

一、四个阶段和拓展点

SpringBean的生命周期和拓展点.jpg

image.png

1.四个阶段

SpringBean有且只有四个阶段,这四个阶段和对应的拓展点柔和在一起。实例化和属性赋值对应的构造方法和setter方法的注入。初始化和销毁是用户可以自定义的两个阶段。
主要逻辑都在doCreateBean方法中。

  1. // 忽略了无关代码
  2. protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
  3. throws BeanCreationException {
  4. // Instantiate the bean.
  5. BeanWrapper instanceWrapper = null;
  6. if (instanceWrapper == null) {
  7. // 实例化阶段!
  8. instanceWrapper = createBeanInstance(beanName, mbd, args);
  9. }
  10. // Initialize the bean instance.
  11. Object exposedObject = bean;
  12. try {
  13. // 属性赋值阶段!
  14. populateBean(beanName, mbd, instanceWrapper);
  15. // 初始化阶段!
  16. exposedObject = initializeBean(beanName, exposedObject, mbd);
  17. }
  18. }

2.常用拓展点

2.1影响多个Bean的接口

实现了这些接口的Bean会切入到多个Bean的生命周期中。正因为如此,这些接口的功能非常强大,Spring内部扩展也经常使用这些接口,例如自动注入以及AOP的实现都和他们有关。

  • BeanPostProcessor
  • InstantiationAwareBeanPostProcessor

这两兄弟可能是Spring扩展中最重要的两个接口!InstantiationAwareBeanPostProcessor作用于实例化阶段的前后,BeanPostProcessor作用于初始化阶段的前后。正好和第一、第三个生命周期阶段对应。
InstantiationAwareBeanPostProcessor实际上继承了BeanPostProcessor接口,严格意义上来看他们不是两兄弟,而是两父子。但是从生命周期角度我们重点关注其特有的对实例化阶段的影响,图中省略了从BeanPostProcessor继承的方法。

InstantiationAwareBeanPostProcessor extends BeanPostProcessor

InstantiationAwareBeanPostProcessor源码分析:
  • postProcessBeforeInstantiation调用点,忽略无关代码: ```java @Override protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { try {

      // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
      // postProcessBeforeInstantiation方法调用点,这里就不跟进了,
      // 有兴趣的同学可以自己看下,就是for循环调用所有的InstantiationAwareBeanPostProcessor
      Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
      if (bean != null) {
          return bean;
      }
    

    }

    try {

      // 上文提到的doCreateBean方法,可以看到
      // postProcessBeforeInstantiation方法在创建Bean之前调用
      Object beanInstance = doCreateBean(beanName, mbdToUse, args);
      if (logger.isTraceEnabled()) {
          logger.trace("Finished creating instance of bean '" + beanName + "'");
      }
      return beanInstance;
    

    }

}


- postProcessAfterInstantiation调用点,忽略无关代码:
```java
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
   // 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;
    // InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation()
    // 方法作为属性赋值的前置检查条件,在属性赋值之前执行,能够影响是否进行属性赋值!
   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;
            }
         }
      }
   }
   // 忽略后续的属性赋值操作代码
}


2.2只调一次的接口

这一大类接口的特点是功能丰富,常用于用户自定义扩展。
第二大类中又可以分为两类:

  1. Aware类型的接口
  2. 生命周期接口(InitializingBean、DisposableBean)

调用时机需要注意:所有的Aware方法都是在初始化阶段之前调用的!
Aware Group1

  1. BeanNameAware
  2. BeanClassLoaderAware
  3. BeanFactoryAware

Aware Group2

  1. EnvironmentAware
  2. EmbeddedValueResolverAware 这个知道的人可能不多,实现该接口能够获取Spring EL解析器,用户的自定义注解需要支持spel表达式的时候可以使用,非常方便。
  3. ApplicationContextAware(ResourceLoaderAware\ApplicationEventPublisherAware\MessageSourceAware) 这几个接口可能让人有点懵,实际上这几个接口可以一起记,其返回值实质上都是当前的ApplicationContext对象,因为ApplicationContext是一个复合接口,如下:
    public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
         MessageSource, ApplicationEventPublisher, ResourcePatternResolver {}
    

Aware调用时机源码分析
// 见名知意,初始化阶段调用的方法
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
    // 这里调用的是Group1中的三个Bean开头的Aware
    invokeAwareMethods(beanName, bean);
    Object wrappedBean = bean;

    // 这里调用的是Group2中的几个Aware,
    // 而实质上这里就是前面所说的BeanPostProcessor的调用点!
    // 也就是说与Group1中的Aware不同,这里是通过BeanPostProcessor(ApplicationContextAwareProcessor)实现的。
    wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    // 下文即将介绍的InitializingBean调用点
    invokeInitMethods(beanName, wrappedBean, mbd);
    // BeanPostProcessor的另一个调用点
    wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    return wrappedBean;
}

二、BeanPostProcessor接口

作用

如果我们需要在Spring容器完成Bean的实例化、配置和其他的初始化前后添加一些自己的逻辑处理,我们就可以定义一个或者多个BeanPostProcessor接口的实现,然后注册到容器中。
配置了后置处理器,不管是实例化哪个Bean,都会先调用 postProcessBeforeInitialization方法。
Spring容器中所有的注册的bean都会调用这个接口的实现

5.前bean===PROPAGATION_REQUIRED,ISOLATION_DEFAULT-------transactionTemplate
7.后bean===PROPAGATION_REQUIRED,ISOLATION_DEFAULT-------transactionTemplate
5.前bean===org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration$$EnhancerBySpringCGLIB$$9baebd77@781711b7-------org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration
7.后bean===org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration$$EnhancerBySpringCGLIB$$9baebd77@781711b7-------org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration
2019-07-29 18:45:56.894  INFO 20108 --- [           main] com.aliyun.devata.testmoudel.TestMq      : Started TestMq in 20.563 seconds (JVM running for 28.885)
5.前bean===com.aliyun.devata.testmoudel.TestMq@1e461e41-------com.aliyun.devata.testmoudel.TestMq
7.后bean===com.aliyun.devata.testmoudel.TestMq@1e461e41-------com.aliyun.devata.testmoudel.TestMq

注意

1、接口中的两个方法都要将传入的bean返回,而不能返回null,如果返回的是null那么我们通过getBean方法将得不到目标。
2、BeanFactory和ApplicationContext对待bean后置处理器稍有不同。ApplicationContext会自动检测在配置文件中实现了BeanPostProcessor接口的所有bean,并把它们注册为后置处理器,然后在容器创建bean的适当时候调用它,因此部署一个后置处理器同部署其他的bean并没有什么区别。而使用BeanFactory实现的时候,bean 后置处理器必须通过代码显式地去注册,在IoC容器继承体系中的ConfigurableBeanFactory接口中定义了注册方法:

void addBeanPostProcessor(BeanPostProcessor beanPostProcessor);

3、不要将BeanPostProcessor标记为延迟初始化。因为如果这样做,Spring容器将不会注册它们,自定义逻辑也就无法得到应用。假如你在元素的定义中使用了’default-lazy-init’属性,请确信你的各个BeanPostProcessor标记为’lazy-init=”false”‘。

使用场景

记录每个对象被实例化的时间
过滤每个调用对象的IP
给所有对象添加一个属性,获取其他的函数(所谓AOP,面向切面编程,针对所有对象编程)

@Component
public class UserService implements BeanNameAware, BeanFactoryAware, ApplicationContextAware , InitializingBean {
    public UserService() {
        System.out.println("1.自定义的构造器");
    }

    @Override
    public void setBeanName(String s) {
        System.out.println("2.当前Bean的ID号为:" + s);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("3.当前beanFactory"+beanFactory);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("4.当前applicationContext"+applicationContext);
    }

    @PostConstruct
    public void init(){
        System.out.println("6.1================自定义的初始化注解标签@PostConstruct");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("6.2================afterPropertiesSet");
        System.out.println("6.3================自定义的初始化配置文件init-method");
    }
}
@Component
public class CustomerBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("5.前bean==="+bean+"-------"+beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("7.后bean==="+bean+"-------"+beanName);
        return bean;
    }
}

执行输出

1.自定义的构造器
2.当前Bean的ID号为:userService
3.当前beanFactoryorg.springframework.beans.factory.support.DefaultListableBeanFactory@7a55f148: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListenerFactory,org.springframework.boot.test.mock.mockito.MockitoPostProcessor$SpyPostProcessor,org.springframework.boot.test.mock.mockito.MockitoPostProcessor,application,org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory,searchServiceImpl,producter,customerBeanPostProcessor,customerManagerListener,diamondService,userService,messageHandlerServiceImpl,queryMappingConfigServiceImpl,wormholeMetaqTopicDataServiceImpl,topicClientDispatcher,currentLimitedModes,serviceCheckUtils,topicConfigUtils,elasticsearchRestClient,elasticsearchConnectionConfig,dataSourceConfig,postgreConnectionConfig,lockService,tairWrapper,searchServiceImpl#HSFProvider,restClientBuilder,highLevelClient,restClient,wormholePostgreDataSource,wormholePostgreTransactionManager,wormholePostgreSqlSessionFactory,wormholePostgreSqlSessionTemplate,wormholePostgreJdbcTemplate,tagUniqueCodeIndexMappingMapper,wormholeGroovyScriptMapper,wormholeMetaqTopicDataMapper,org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration,org.springframework.transaction.config.internalTransactionAdvisor,transactionAttributeSource,transactionInterceptor,org.springframework.transaction.config.internalTransactionalEventListenerFactory,org.springframework.boot.autoconfigure.AutoConfigurationPackages,org.springframework.aop.config.internalAutoProxyCreator,com.alibaba.rhino.boot.keycenter.KeyCenterHttpAutoConfiguration,keyStore,org.springframework.boot.autoconfigure.condition.BeanTypeRegistry,cryptograph,spring.keycenter-com.alibaba.rhino.boot.keycenter.KeyCenterHttpProperties,org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor,org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.store,org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,propertySourcesPlaceholderConfigurer,com.alibaba.boot.hsf.consumer.HsfConsumerAutoConfiguration,hsfConsumerPostProcessor,com.alibaba.druid.spring.boot.autoconfigure.stat.DruidFilterConfiguration,statFilter,com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure,spring.datasource.druid-com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties,spring.datasource-org.springframework.boot.autoconfigure.jdbc.DataSourceProperties,com.taobao.pandora.boot.spring.LoggerConflictDetector,com.taobao.pandora.boot.springboot2.PandoraAutoConfiguration,org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadataProvidersConfiguration$TomcatDataSourcePoolMetadataProviderConfiguration,tomcatPoolDataSourceMetadataProvider,org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadataProvidersConfiguration,org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,dataSourceInitializer,dataSourceInitializerPostProcessor,org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration,mybatis-org.mybatis.spring.boot.autoconfigure.MybatisProperties,org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,persistenceExceptionTranslationPostProcessor,org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,gson,org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,spring.info-org.springframework.boot.autoconfigure.info.ProjectInfoProperties,org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration$DataSourceTransactionManagerConfiguration,org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,namedParameterJdbcTemplate,org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration$TransactionTemplateConfiguration,transactionTemplate,org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,platformTransactionManagerCustomizers,spring.transaction-org.springframework.boot.autoconfigure.transaction.TransactionProperties,org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration]; root of factory hierarchy
4.当前applicationContextorg.springframework.context.annotation.AnnotationConfigApplicationContext@68e62ca4: startup date [Mon Jul 29 18:45:44 CST 2019]; root of context hierarchy
5.前bean===com.aliyun.devata.wormhole.search.service.middleware.UserService@60d6fdd4-------userService
6.1================自定义的初始化注解标签@PostConstruct
6.2================afterPropertiesSet
6.3================自定义的初始化配置文件init-method
7.后bean===com.aliyun.devata.wormhole.search.service.middleware.UserService@60d6fdd4-------userService

BeanPostProcessor 注册时机与执行顺序

我们知道BeanPostProcessor也会注册为Bean,那么Spring是如何保证BeanPostProcessor在我们的业务Bean之前初始化完成呢?
请看我们熟悉的refresh()方法的源码,省略部分无关代码:

@Override
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        try {
            // Allows post-processing of the bean factory in context subclasses.
            postProcessBeanFactory(beanFactory);
            // Invoke factory processors registered as beans in the context.
            invokeBeanFactoryPostProcessors(beanFactory);
            // Register bean processors that intercept bean creation.
            // 所有BeanPostProcesser初始化的调用点
            registerBeanPostProcessors(beanFactory);
            // Initialize message source for this context.
            initMessageSource();
            // Initialize event multicaster for this context.
            initApplicationEventMulticaster();
            // Initialize other special beans in specific context subclasses.
            onRefresh();
            // Check for listener beans and register them.
            registerListeners();
            // Instantiate all remaining (non-lazy-init) singletons.
            // 所有单例非懒加载Bean的调用点
            finishBeanFactoryInitialization(beanFactory);
            // Last step: publish corresponding event.
            finishRefresh();
        }
    }

可以看出,Spring是先执行registerBeanPostProcessors()进行BeanPostProcessors的注册,然后再执行finishBeanFactoryInitialization初始化我们的单例非懒加载的Bean。

执行顺序

BeanPostProcessor有很多个,而且每个BeanPostProcessor都影响多个Bean,其执行顺序至关重要,必须能够控制其执行顺序才行。关于执行顺序这里需要引入两个排序相关的接口:PriorityOrdered、Ordered

  • PriorityOrdered是一等公民,首先被执行,PriorityOrdered公民之间通过接口返回值排序
  • Ordered是二等公民,然后执行,Ordered公民之间通过接口返回值排序
  • 都没有实现是三等公民,最后执行

在以下源码中,可以很清晰的看到Spring注册各种类型BeanPostProcessor的逻辑,根据实现不同排序接口进行分组。优先级高的先加入,优先级低的后加入。

// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
// 首先,加入实现了PriorityOrdered接口的BeanPostProcessors,顺便根据PriorityOrdered排了序
String[] postProcessorNames =
    beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
    if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
        currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
        processedBeans.add(ppName);
    }
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
// 然后,加入实现了Ordered接口的BeanPostProcessors,顺便根据Ordered排了序
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
    if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
        currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
        processedBeans.add(ppName);
    }
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
// 最后加入其他常规的BeanPostProcessors
boolean reiterate = true;
while (reiterate) {
    reiterate = false;
    postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
    for (String ppName : postProcessorNames) {
        if (!processedBeans.contains(ppName)) {
            currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
            processedBeans.add(ppName);
            reiterate = true;
        }
    }
    sortPostProcessors(currentRegistryProcessors, beanFactory);
    registryProcessors.addAll(currentRegistryProcessors);
    invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
    currentRegistryProcessors.clear();
}

根据排序接口返回值排序,默认升序排序,返回值越低优先级越高。

/**
  * Useful constant for the highest precedence value.
  * @see java.lang.Integer#MIN_VALUE
  */
int HIGHEST_PRECEDENCE = Integer.MIN_VALUE;
/**
  * Useful constant for the lowest precedence value.
  * @see java.lang.Integer#MAX_VALUE
  */
int LOWEST_PRECEDENCE = Integer.MAX_VALUE;

PriorityOrdered、Ordered接口作为Spring整个框架通用的排序接口,在Spring中应用广泛,也是非常重要的接口。

image.png

二、ApplicationContext和BeanFactory

SpringBean的生命周期 - 图6BeanFactory介绍

则当你实例化该对象的时候,配置的Bean不会被马上实例化,当你使用的时候才被实例化。BeanFacotry会延迟加载所有的Bean。这样的好处是节约内存,缺点是速度。

BeanFactory 是 Spring 的“心脏”。它就是 Spring IoC 容器的真面目。Spring 使用 BeanFactory 来实例化、配置和管理 Bean。

BeanFactory:是IOC容器的核心接口, 它定义了IOC的基本功能,我们看到它主要定义了getBean方法。getBean方法是IOC容器获取bean对象和引发依赖注入的起点。方法的功能是返回特定的名称的Bean。

BeanFactory 是初始化 Bean 和调用它们生命周期方法的“吃苦耐劳者”。注意,BeanFactory 只能管理单例(Singleton)Bean 的生命周期。它不能管理原型(prototype,非单例)Bean 的生命周期。这是因为原型 Bean 实例被创建之后便被传给了客户端,容器失去了对它们的引用。

BeanFactory最常见的实现类为XmlBeanFactory,可以从classpath或文件系统等获取资源。

(1)File file = new File("fileSystemConfig.xml");
Resource resource = new FileSystemResource(file);
BeanFactory beanFactory = new XmlBeanFactory(resource);
(2)
Resource resource = new ClassPathResource("classpath.xml"); 
BeanFactory beanFactory = new XmlBeanFactory(resource);

通过BeanFactory启动IoC容器时,并不会初始化配置文件中定义的Bean,初始化动作发生在第一个调用时。
对于单实例(singleton)的Bean来说,BeanFactory会缓存Bean实例,所以第二次使用getBean时直接从IoC容器缓存中获取Bean。

ApplicationContext介绍

则配置的Bean如果scope属性是singleton,那么当容器被加载时,这些Bean就会被实例化。好处是可以预先加载,速度快;缺点是耗内存。

ApplicationContext拓展功能:

1.提供文本解析工具,包括对国际化的支持
2.提供载入文件资源的通用方法,如图片。
3.可以向注册为监听器的bean发送事件。

ApplicationContext三种经常用到的实现:

1.ClassPathXmlApplicationContext:从类路径中加载。
2.FileSystemXmlApplicationContext:从文件系统加载。
3.XmlWebApplicationContext:从Web系统中加载。

/第一种加载方法,加载的是classpath下的配置文件。
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//第二种加载方法,加载的是磁盘路径下的文件。
ApplicationContext applicationContext = new FileSystemXmlApplicationContext("applicationContext.xml");
//第三种加载方法,XmlWebApplicationContext,从web系统中加载。
ApplicationContext context1 = WebApplicationContextUtils.getWebApplicationContext(ServletContext sc);
ApplicationContext context2 = WebApplicationContextUtils.getRequiredWebApplicationContext(ServletContext sc);
WebApplicationContext webApplicationContext = (WebApplicationContext) servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);

//得到配置文件后,就能拿到想要的对象。例如:
HelloService helloService = (HelloService) applicationContext.getBean("userService");
//在这当中getBean中的参数为你在配置文件下,这个对象的id,一个标识。

三、Spring中bean实例化的三种方式

普通构造方法创建

public class User {
    public void add() {
        System.out.println("add()---------");
    }
}

<bean class="org.sang.User" id="user"/>

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) context.getBean("user");
System.out.println(user);

静态工厂创建

public class User2 {
    public void add() {
        System.out.println("add2()---------");
    }
}

public class User2Factory {
    public static User2 getInstance() {
        return new User2();
    }
}

<bean id="user2" class="org.sang.User2Factory" factory-method="getInstance"/>

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User2 user = (User2) context.getBean("user2");
user.add();

实例工厂创建

public class User3 {
    public void add() {
        System.out.println("add3()---------");
    }
}

public class User3Factory {
    public User3 getUser3() {
        return new User3();
    }
}

<bean class="org.sang.User3Factory" id="user3Factory"/>
 <bean id="user3" factory-bean="user3Factory" factory-method="getUser3"/>

四、依赖注入

1) field注入

@Controller
public class FooController {
  @Autowired
  private FooService fooService;

  public List<Foo> listFoo() {
      return fooService.list();
  }
}

2) 构造器注入

@Controller
public class FooController {

  private final FooService fooService;

  @Autowired
  public FooController(FooService fooService) {
      this.fooService = fooService;
  }

}

或者

@Controller
public class FooController {

  private final FooService fooService;
  // 当只有一个参数时可不写@Autowired
  public FooController(FooService fooService) {
      this.fooService = fooService;
  }
}

在Spring4.x版本中推荐的注入方式就是这种

3) setter注入

@Controller
public class FooController {

  private FooService fooService;

  @Autowired
  public void setFooService(FooService fooService) {
      this.fooService = fooService;
  }
}

在Spring3.x刚推出的时候,推荐使用注入的就是这种

为什么Spring4.x推荐构造函数注入

在上面的分析看来,构造函数注入好像并没有显现出来它的优势,但问什么Spring4.x会推翻之前推荐的setter注入,采用构造函数注入呢?官方的理由汇总如下:

  • 依赖不可变:加入了final来约束修饰Field,这条是很显然的;
  • 依赖不可为空:在实例化的时候会检查构造函数参数是否为空,如果为空(未找到改类型的实例对象)则会抛出异常。
  • 单一职责:当使用构造函数注入时,如果参数过多,你会发现当前类的职责过大,需要进行拆分。而使用Field注入时,你并不会意识到此问题。
  • 更利于单元测试:按照其他两种方式注入,当单元测试时需要初始化整个spring的环境,而采用构造方法注入时,只需要初始化需要的类即可,即可以直接实例化需要的类。
  • 避免IOC容器以外环境调用时潜在的NPE(空指针异常)。
  • 避免循环依赖。
  • 保证返回客户端(调用)的代码的时候是完全初始化的状态。