IOC的两种实现方式:依赖查找(DL)和依赖注入(DI)。
DI和DL的区别在于依赖的对象是否为主动获取,是的话,就是依赖查找,否则就是依赖注入,由框架绑定完成。如下面例子中的UserRepository,两者在main函数中没有区别,都是通过Context上下文API实现的;

依赖查找的例子

dependency-lookup-context.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans
  3. xmlns="http://www.springframework.org/schema/beans"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  6. xsi:schemaLocation="http://www.springframework.org/schema/beans
  7. https://www.springframework.org/schema/beans/spring-beans.xsd
  8. http://www.springframework.org/schema/context
  9. https://www.springframework.org/schema/context/spring-context.xsd">
  10. <!-- <context:annotation-config/>-->
  11. <!-- <context:component-scan base-package="org.acme" />-->
  12. <!-- Root BeanDefinition 不需要合并,不存在 parent -->
  13. <!-- 普通 beanDefinition GenericBeanDefinition -->
  14. <!-- 经过合并后 GenericBeanDefinition 变成 RootBeanDefinition -->
  15. <bean id="user" class="org.geekbang.thinking.in.spring.ioc.overview.domain.User">
  16. <property name="id" value="1"/>
  17. <property name="name" value="小马哥"/>
  18. <property name="city" value="HANGZHOU"/>
  19. <property name="workCities" value="BEIJING,HANGZHOU"/>
  20. <property name="lifeCities">
  21. <list>
  22. <value>BEIJING</value>
  23. <value>SHANGHAI</value>
  24. </list>
  25. </property>
  26. <property name="configFileLocation" value="classpath:/META-INF/user-config.properties"/>
  27. </bean>
  28. <!-- 普通 beanDefinition GenericBeanDefinition -->
  29. <!-- 合并后 GenericBeanDefinition 变成 RootBeanDefinition,并且覆盖 parent 相关配置-->
  30. <!-- primary = true , 增加了一个 address 属性 -->
  31. <bean id="superUser" class="org.geekbang.thinking.in.spring.ioc.overview.domain.SuperUser" parent="user"
  32. primary="true">
  33. <property name="address" value="杭州"/>
  34. </bean>
  35. <bean id="objectFactory" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
  36. <property name="targetBeanName" value="user"/>
  37. </bean>
  38. </beans>

User

  1. public class User implements BeanNameAware {
  2. private Long id;
  3. private String name;
  4. private City city;
  5. private City[] workCities;
  6. private List<City> lifeCities;
  7. private Resource configFileLocation;
  8. private Company company;
  9. private Properties context;
  10. private String contextAsText;
  11. /**
  12. * 当前 Bean 的名称
  13. */
  14. private transient String beanName;
  15. public Long getId() {
  16. return id;
  17. }
  18. public void setId(Long id) {
  19. this.id = id;
  20. }
  21. public String getName() {
  22. return name;
  23. }
  24. public void setName(String name) {
  25. this.name = name;
  26. }
  27. public City getCity() {
  28. return city;
  29. }
  30. public void setCity(City city) {
  31. this.city = city;
  32. }
  33. public Resource getConfigFileLocation() {
  34. return configFileLocation;
  35. }
  36. public void setConfigFileLocation(Resource configFileLocation) {
  37. this.configFileLocation = configFileLocation;
  38. }
  39. public City[] getWorkCities() {
  40. return workCities;
  41. }
  42. public void setWorkCities(City[] workCities) {
  43. this.workCities = workCities;
  44. }
  45. public List<City> getLifeCities() {
  46. return lifeCities;
  47. }
  48. public void setLifeCities(List<City> lifeCities) {
  49. this.lifeCities = lifeCities;
  50. }
  51. public Company getCompany() {
  52. return company;
  53. }
  54. public void setCompany(Company company) {
  55. this.company = company;
  56. }
  57. public static User createUser() {
  58. User user = new User();
  59. user.setId(1L);
  60. user.setName("小马哥");
  61. return user;
  62. }
  63. @PostConstruct
  64. public void init() {
  65. System.out.println("User Bean [" + beanName + "] 初始化...");
  66. }
  67. @PreDestroy
  68. public void destroy() {
  69. System.out.println("User Bean [" + beanName + "] 销毁中...");
  70. }
  71. @Override
  72. public void setBeanName(String name) {
  73. this.beanName = name;
  74. }
  75. public Properties getContext() {
  76. return context;
  77. }
  78. public void setContext(Properties context) {
  79. this.context = context;
  80. }
  81. public String getContextAsText() {
  82. return contextAsText;
  83. }
  84. public void setContextAsText(String contextAsText) {
  85. this.contextAsText = contextAsText;
  86. }
  87. @Override
  88. public String toString() {
  89. return "User{" +
  90. "id=" + id +
  91. ", name='" + name + '\'' +
  92. ", city=" + city +
  93. ", workCities=" + Arrays.toString(workCities) +
  94. ", lifeCities=" + lifeCities +
  95. ", configFileLocation=" + configFileLocation +
  96. ", company=" + company +
  97. ", context=" + context +
  98. ", contextAsText='" + contextAsText + '\'' +
  99. ", beanName='" + beanName + '\'' +
  100. '}';
  101. }

SuperUser

  1. @Super
  2. public class SuperUser extends User {
  3. private String address;
  4. public String getAddress() {
  5. return address;
  6. }
  7. public void setAddress(String address) {
  8. this.address = address;
  9. }
  10. @Override
  11. public String toString() {
  12. return "SuperUser{" +
  13. "address='" + address + '\'' +
  14. "} " + super.toString();
  15. }
  16. }
  1. public static void main(String[] args) {
  2. // 配置 XML 配置文件
  3. // 启动 Spring 应用上下文
  4. BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/dependency-lookup-context.xml");
  5. // 按照类型查找
  6. lookupByType(beanFactory);
  7. // 按照类型查找结合对象
  8. lookupCollectionByType(beanFactory);
  9. // 通过注解查找对象
  10. lookupByAnnotationType(beanFactory);
  11. // lookupInRealTime(beanFactory);
  12. // lookupInLazy(beanFactory);
  13. }
  14. private static void lookupByAnnotationType(BeanFactory beanFactory) {
  15. if (beanFactory instanceof ListableBeanFactory) {
  16. ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
  17. Map<String, User> users = (Map) listableBeanFactory.getBeansWithAnnotation(Super.class);
  18. System.out.println("查找标注 @Super 所有的 User 集合对象:" + users);
  19. }
  20. }
  21. private static void lookupCollectionByType(BeanFactory beanFactory) {
  22. if (beanFactory instanceof ListableBeanFactory) {
  23. ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
  24. Map<String, User> users = listableBeanFactory.getBeansOfType(User.class);
  25. System.out.println("查找到的所有的 User 集合对象:" + users);
  26. }
  27. }
  28. private static void lookupByType(BeanFactory beanFactory) {
  29. User user = beanFactory.getBean(User.class);
  30. System.out.println("实时查找:" + user);
  31. }
  32. private static void lookupInLazy(BeanFactory beanFactory) {
  33. ObjectFactory<User> objectFactory = (ObjectFactory<User>) beanFactory.getBean("objectFactory");
  34. User user = objectFactory.getObject();
  35. System.out.println("延迟查找:" + user);
  36. }
  37. private static void lookupInRealTime(BeanFactory beanFactory) {
  38. User user = (User) beanFactory.getBean("user");
  39. System.out.println("实时查找:" + user);
  40. }

依赖注入的例子

dependency-injection-context.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:util="http://www.springframework.org/schema/util"
  5. xsi:schemaLocation="
  6. http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
  7. http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">
  8. <!-- 通过导入复用 dependency-lookup-context.xml -->
  9. <import resource="dependency-lookup-context.xml"/>
  10. <bean id="userRepository" class="org.geekbang.thinking.in.spring.ioc.overview.repository.UserRepository"
  11. autowire="byType"> <!-- Auto-Wiring -->
  12. <!-- 手动配置 -->
  13. <!-- <property name="users">-->
  14. <!-- <util:list>-->
  15. <!-- <ref bean="superUser" />-->
  16. <!-- <ref bean="user" />-->
  17. <!-- </util:list>-->
  18. <!-- </property>-->
  19. </bean>
  20. </beans>

UserRepository

  1. public class UserRepository {
  2. private Collection<User> users; // 自定义 Bean
  3. private BeanFactory beanFactory; // 內建非 Bean 对象(依赖)
  4. private ObjectFactory<ApplicationContext> objectFactory;
  5. public Collection<User> getUsers() {
  6. return users;
  7. }
  8. public void setUsers(Collection<User> users) {
  9. this.users = users;
  10. }
  11. public void setBeanFactory(BeanFactory beanFactory) {
  12. this.beanFactory = beanFactory;
  13. }
  14. public BeanFactory getBeanFactory() {
  15. return beanFactory;
  16. }
  17. public ObjectFactory<ApplicationContext> getObjectFactory() {
  18. return objectFactory;
  19. }
  20. public void setObjectFactory(ObjectFactory<ApplicationContext> objectFactory) {
  21. this.objectFactory = objectFactory;
  22. }
  23. }
  1. public static void main(String[] args) {
  2. // 配置 XML 配置文件
  3. // 启动 Spring 应用上下文
  4. // BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/dependency-injection-context.xml");
  5. ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:/META-INF/dependency-injection-context.xml");
  6. // 依赖来源一:自定义 Bean
  7. UserRepository userRepository = applicationContext.getBean("userRepository", UserRepository.class);
  8. // System.out.println(userRepository.getUsers());
  9. // 依赖来源二:依赖注入(內建依赖)
  10. System.out.println(userRepository.getBeanFactory());
  11. ObjectFactory userFactory = userRepository.getObjectFactory();
  12. System.out.println(userFactory.getObject() == applicationContext);
  13. // 依赖查找(错误)
  14. // System.out.println(beanFactory.getBean(BeanFactory.class));
  15. // 依赖来源三:容器內建 Bean
  16. Environment environment = applicationContext.getBean(Environment.class);
  17. System.out.println("获取 Environment 类型的 Bean:" + environment);
  18. }
  19. private static void whoIsIoCContainer(UserRepository userRepository, ApplicationContext applicationContext) {
  20. // ConfigurableApplicationContext <- ApplicationContext <- BeanFactory
  21. // ConfigurableApplicationContext#getBeanFactory()
  22. // 这个表达式为什么不会成立
  23. System.out.println(userRepository.getBeanFactory() == applicationContext);
  24. // ApplicationContext is BeanFactory
  25. }