一、SpringIoC
IoC有两种方式,一种是DI,另一种是DL
DI: 当前软件实体被动接受其依赖的其他组件被IoC容器注入
DL: 当前软件实体主动去某个服务注册地查找其依赖的服务
使用SpringIoC容器的一个典型代码片段:
public class App{
public static void main(String[] args){
ApplciationContext context = new FileSystemXmlApplicationContext("……");
//……
MockService service = context.getBean(MockService.class);
service.doSomething();
}
}
任何一个使用Spring框架构建的独立java应用,通常都会存在一行类似于context.getBean(…)的代码,这行代码做的就是DL的工作。
而构建的任何一中IoC容器背后(如BeanFactory或者applicationContext)发生的事情,则更多的是DI过程
IoC容器中发生的事情:
(一)收集和注册
- 通过XML 或java代码的方式定义一些Bean
- 通过手动组装或者让容器基于某些机制自动扫描的形式,将这些Bean定义收集到IoC容器中。
XML形式
<bean id="mockService" class="..MockServiceImpl">
...
</bean>
批量收集并注册:XML Schema形式
<context:component-scan base-package="com.keevol">
</context:component-scan>
(二)分析和组装
- 分析已经在IoC容器中的Bean
- 根据之间的依赖关系先后组装它们
最早通过xml配置文件来描述Bean与Bean之间的关系
后来基于java代码和annotation元信息描述(@Autowire)
二、JavaConfig
基于Java代码和Annotation元信息的依赖关系绑定描述方式,即JavaConfig项目
基于javaconfig方式的依赖关系绑定描述基本上映射了最早的基于xml的配置方式:
-
表达形式层面
XML:
<? xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLScheme-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean定义--> </beans>
JavaConfig:
@Configuration public class MockConfiguration{ //bean定义 }
任何一个标注了@Configuration的java类定义都是一个javaconfig配置类。
-
注册Bean定义层面
XML:
<bean id="mockService" class="..MockServiceImpl"> ... </bean>
JavaConfig:
@Configuration public class MockConfiguration{ @Bean public MockService mockService(){ return new MockServiceImpl(); } }
任何一个标注了@Bean的方法,其返回值将作为一个Bean定义注册到Spring的IoC容器,方法名默认成为该Bean定义的id
-
表达依赖注入关系层面
XML:
<bean id="mockService" class="..MockServiceImpl"> <property name="dependencyService" ref="dependencyService"/> </bean> <bean id="dependencyService" class="DependencyServiceImpl"/>
JavaConfig:
@Configuration public class MockConfiguration{ @Bean public MockService mockService(){ return new MockServiceImpl(dependencyService()); } @Bean public DependencyService dependencyService(){ return new DependencyServiceImpl(); } }
注意
在javaConfig形式的依赖注入的过程中,我们使用方法调用的形式注入依赖。如果多于一个bean需要依赖这个方法调用返回的对象实例,是否意味着需要创建多个同一类型的对象实例?
实际上,依赖注入的都是同一个Singleton对象实例。
Spring通过拦截配置类的方法调用来避免多次初始化同一类型对象的问题,一旦拥有拦截逻辑的子类发现当前方法没有对应的类型实例时才会去请求父类的同一方法来初始化对象实例,否则直接返回之前的对象实例
(一)Annotation
1、@Component Scan
@Component Scan对应XMl中的< context:componet-scan>元素。用于配合一些元信息,如@Component和@Repository等,将标注了这些元信息的Bean定义类批量采集到Spring的IoC容器中。
可以通过backPackages等属性来细粒度的设置其自动扫描的范围,如果不指定则默认实现从声明@Component Scan所在类的package进行扫描。
2、@PropertySource和@PropertySources
@PropertySource用于从某些地方加载*.properties文件内容,并将其中的属性加载到IoC容器中,便于填充一些Bean定义属性的占位符。
如果使用Java8或更高版本开发,可以并行声明多个@PropertySource
@Configuration
@PropertySource("classpath:1.properties")
@PropertySource("classpath:2.properties")
@PropertySource("...")
public class XConfiguration{
...
}
如果使用低于Java8版本开发,想声明多个@PropertySource,则需要借助@PropertySources
@PropertySources({
@PropertySource("classpath:1.properties")
@PropertySource("classpath:2.properties")
...
})
public class XConfiguration{
...
}
3、@Import和@ImportResource
在xml中通过< import resource=“XXX.xml”/>的形式将多个分开的容器配置合并到一个配置中,在javaconfig中使用@import
@Configuration
@Import(MockConfiguration.class)
public class XConfiguration{
...
}
@Import只负责引入javaconfig形式定义的IoC容器配置,如果有一些遗留的配置或者遗留系统需要以XML形式来配置,依然可以通过@ImportResource将他们合并到javaconfig配置的容器中:
@Configuration
@Import(MockConfigutation.class)
@ImportResource("...")
public class XCofiguration{
...
}