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;
}
}