IoC容器
Inversion of Control.
Spring的核心就是提供了一个IoC容器,它可以管理所有轻量级的JavaBean组件,提供的底层服务包括组件的生命周期管理、配置和组装服务、AOP支持,以及建立在AOP基础上的声明式事务服务等。 - 将组件的创建+配置与组件的使用相分离 - 共享组件
基础
- BeanFactory: a basic IoC container interface which a parent interface of ApplicationContext.
@SpringBootApplication
// Main class
public class DemoApplication 
{
// Main driver method
  public static void main(String[] args) 
  {
    // Creating object in a spring container (Beans)
    BeanFactory factory = new ClassPathXmlApplicationContext("bean-factory-demo.xml");
    Student student = (Student) factory.getBean("student"); // 或者是 context.getBean("name", Class<T> requiredType)
    System.out.println(student);
  }
}
- ApplicationContext: is the sub-interface of BeanFactory. 它 provides 一些 enterprise-specific functionalities, 所以开发者一般使用这个。- 在加载上,BeanFactory在初始化容器的时候,并未实例化Bean,直到需要使用某个Bean(调用getBean()方法) 时才实例目标Bean,导致不能及时发现可能存在的一些配置上的问题。ApplicationContext 则在初始化应用上下文时就实例化所有单实例的Bean,有助于发现配置问题及提高运行时速度;但它占用内存空间,配置的Bean较多时,启动会比较慢。
 
装配 Bean
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
Spring容器就是ApplicationContext,它是一个接口,有很多实现类,如ClassPathXmlApplicationContext,表示它会自动从classpath中查找指定的XML配置文件。
获得了ApplicationContext的实例,就获得了IoC容器的引用。从ApplicationContext中可以根据Bean的ID或者Bean的类型获取Bean的引用。
可以注入给 interface 或者 enum 吗?
不行,因为它们是 final. First of all, public static non-final fields are evil. Spring does not allow injecting to such fields for a reason.
Annotation
简化 xml 的配置
@Configuration
@ComponentScan
public class AppConfig {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        UserService userService = context.getBean(UserService.class);
        User user = userService.login("bob@example.com", "password");
        System.out.println(user.getName());
    }
}
定制 Bean
scope
- 默认:单例
- 原型:我们每次调用getBean(Class),容器都返回一个新的实例,这种Bean称为Prototype(原型),它的生命周期显然和Singleton不同。声明一个Prototype的Bean时,需要添加一个额外的@Scope注解
可选注入
@Autowird(required = false)
第三方Bean
@Configuration
@ComponentScan
public class AppConfig {
    // 创建一个Bean:
    @Bean
    ZoneId createZoneId() {
        return ZoneId.of("Z");
    }
}
初始化和销毁
在Bean的初始化和清理方法上标记@PostConstruct和@PreDestroy
别名
可以用@Bean("name")指定别名,也可以用@Bean+@Qualifier("name")指定别名。
Resource与注入配置
- resource: @Value("classpath:/logo.txt")
- 注入配置:容器加注解 @PropertySource("app.properties")
条件装配
在运行程序时,加上JVM参数-Dspring.profiles.active=test就可以指定以test环境启动。
- 在 Bean 上注解:@Profile("test")
实践
获取 ApplicationContext 实例
实现 ApplicationContextAware 接口
public class SpringContextHolder implements ApplicationContextAware {
     @Override
    public void setApplicationContext(ApplicationContext appContext) {
        applicationContext = appContext;
    }
}