前言
IoC其实有两种方式,一种是DI,而另一种是DL,即Dependency Lookup(依赖查找),前者是当前软件实体被动接受其依赖的其他组件被IOc容器注入,而后者是当前软件实体主动去某个服务注册地查找其依赖的那些服务。
我们通常提到的Spring IoC实际上是值Spring框架提供的IoC容器实现(IoC Container),而使用Spring IoC容器的典型代码片段是
1 ApplicationContext ac = new ClassPathXmlApplicationContext("test.xml"); 2 User user = (User) ac.getBean("testBean"); 3 System.out.println(user.getUserName()+"----------"+user.getEmail());
一、任何一个Spring框架构建的独立的Java应用,通常会存在一行类似于sc.getBean()的代码,实际上这个做的就是DL的工作,Spring Ioc所做的事情
1、收集和注册
在本阶段,我们可以使用XML或Java代码的方式定义一些bean,然后通过收到组装或者让容器基于某些机制自动扫描的形式将这些bean定义收集到IoC容器中。
1)以XML格式配置
<bean id="car" class="com.slp.Car"></bean>
2)以XML Schema形式配置进行批量扫描采集和注册
1 <context:component-scan base-package="com.slp">
2、分析和组装
当第一阶段工作完成后,我们可以暂时认为IoC容器中充斥着一个个独立的bean,他们之间没有任何关系,但实际上,他们之间是有依赖关系的,所以,IoC容器在第二阶段做的事情就是分析这些已经在IoC容器中的bean,然后根据他们之间的依赖关系先后组装他们,如果IoC容器发现某个bean依赖于另一个bean,它将会将另一个bean注入依赖他的那么bean,知道所有bean的依赖都注入完成,所有bean都“整装待发”,整个IoC容器的工作即算完成。
至于分析和组装的依据,Sring框架最早是通过XML配置文件的形式来描述bean与bean之间的关系额,随着Java业界研发技术和理念的转变,基于Java代码和Snnotation元信息的描述方式也日渐兴盛(@Autowired和@Inject)但不管是哪种方式,都只是为了简化绑定逻辑描述的各种“表象”,最终都是为本阶段的最终目的服务。
二、了解一点JavaConfig
基于JavaConfig方式额的依赖关系绑定描述基本上映射了最早的基于XML的配置方式
1)表达形式层面
基于XML的配置方式是这样的
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:aop="http://www.springframework.org/schema/aop" 5 xmlns:c="http://www.springframework.org/schema/c" 6 xmlns:context="http://www.springframework.org/schema/context" 7 xmlns:mvc="http://www.springframework.org/schema/mvc" 8 xmlns:p="http://www.springframework.org/schema/p" 9 xmlns:tx="http://www.springframework.org/schema/tx" 10 xmlns:util="http://www.springframework.org/schema/util" 11 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 12 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd 13 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd 14 http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd 15 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd 16 http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd"> 17 18 <bean id="car" class="com.slp.Car"></bean> 19 </beans>
而基于JavaConfig的配置方式是这样的
1 @Configuration 2 public class MockConfiguration{ 3 //bean定义 4 }
任何一个标注了@Configuration的java类定义都是JavaConfig配置类
2)注册bean定义层面
基于XML的配置形式
1 <bean id="test" class="com.slp.Test"> 2 </bean>
而基于JavaConfig的配置形式
1 @Configuration 2 public class MockTest(){ 3 @Bean 4 public Test mockTest(){ 5 return new Test(); 6 } 7 }
任何一个标注了@Bean的方法,其返回值将作为一个bean定义注册到Spring的IoC容器、方法名将默认称为该bean定义的id.
3)表达式依赖注入关系层面
xml形式
1 <bean id="test" class="com.slp.Test"> 2 <property name="dependencyService" ref="user"/> 3 </bean> 4 <bean id="user" class="com.slp.User"/>
而使用JavaConfig的时候是这样的
1 @Configuration 2 public class MockTest{ 3 @Bean 4 public Test mockTest(){ 5 return new Test(); 6 } 7 @Bean 8 public User user(){ 9 return new User(); 10 } 11 }
如果一个bean的定义依赖其他bean,则直接调用对应的JavaConfig类中依赖bean的创建方法就可以了。
三、常用的Annotation
1、@ComponentScan
对应XML配置形式中的<context:component-scan>元素,用于配合一些元信息Java Annotation,比如@Conponent和@Repository等,将标注了这些元信息Annotation的bean定义类批量采集到Spring的IoC容器中。
可以通过basePackage等属性来细粒度的定制@ConponentScan自动扫描的范围,如果不指定则默认Spring框架实现会从声明@ComponentScan所在类的package进行扫描。
2、@PropertySource与@PropertySources
@PropertySource用于从某些地方加载*.properties文件内容,并将其中的属性加载到IoC容器中,便于填充一些bean定义属性的占位符,当然,这需要PropertySourcesPlaceholderConfigurer的配合
1 //Java8或更高版本 2 @Configuration 3 @PropertySource("classpath:1.properties") 4 @PropertySource("classpath:2.properties") 5 public class XConfiguration{ 6 } 7 //低版本 8 @PropertySources({@PropertySource("classpath:1.properties"),@PropertiesSource("classpath:2.properties")}) 9 public class XConfiguration{ 10 }
3、@Import与@ImportResource
在XML形式的配置中,我们通过<import resource="XXX.xml"/>的形式将多个分开的容器配置合到一个配置中,在JavaConfig形式的配置中,我们则使用@Import这个Annotation完成同样目的:
@Configuration
@Import(MockTest.class)
public class XConfiguration{
}
@Import只负责引入JavaConfig形式定义的IoC容器配置,如果有一些遗留的配置或者系统需要以XML形式来配置(比如dubbo框架)我们依然可以通过@ImportResource将他们一起合并到当前JavaConfig配置的容器中。
1 @Configuration 2 @Import(MockTest.class) 3 @ImportResource("...") 4 public class XConfiguration{ 5 }