第三章:Spring IoC 容器概览
1. Spring IoC 依赖查找 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd" > <bean id ="user" class ="com.cruise.thinking.in.spring.ioc.container.overview.domain.User" > <property name ="id" value ="1" > </property > <property name ="name" value ="Cruise" > </property > </bean > <bean id ="objectFactory" class ="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean" > <property name ="targetBeanName" value ="user" > </property > </bean > <bean id ="superUser" class ="com.cruise.thinking.in.spring.ioc.container.overview.domain.SuperUser" parent ="user" primary ="true" > <property name ="address" value ="Beijing" > </property > </bean > </beans >
1 2 3 4 BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/dependency-lookup-context.xml" );
根据 Bean 名称查找 实时查找 1 2 3 4 private static void lookupInRealTime (BeanFactory beanFactory) { User user = (User) beanFactory.getBean("user" ); System.out.println("实时查找:" + user); }
延迟查找 1 2 3 <bean id ="objectFactory" class ="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean" > <property name ="targetBeanName" value ="user" /> </bean >
1 2 3 4 5 private static void lookupInLazy (BeanFactory beanFactory) { ObjectFactory<User> objectFactory = (ObjectFactory<User>) beanFactory.getBean("objectFactory" ); User user = objectFactory.getObject(); System.out.println("延迟查找:" + user); }
根据 Bean 类型查找 单个 Bean 对象 1 2 3 4 private static void lookupByType (BeanFactory beanFactory) { User user = beanFactory.getBean(User.class); System.out.println("实时查找:" + user); }
集合 Bean 对象 1 2 3 4 5 6 7 private static void lookupCollectionByType (BeanFactory beanFactory) { if (beanFactory instanceof ListableBeanFactory) { ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory; Map<String, User> users = listableBeanFactory.getBeansOfType(User.class); System.out.println("查找到的所有的 User 集合对象:" + users); } }
根据 Bean 名称 + 类型查找 1 2 3 4 public static void lookupByNameAndType (BeanFactory beanFactory) { User supperUser = beanFactory.getBean("superUser" , User.class); System.out.println("按照名称和类型查找:" + supperUser); }
根据 Java 注解查找 1 2 3 4 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Super {}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @Super public class SuperUser extends User { private String address; public String getAddress () { return address; } public void setAddress (String address) { this .address = address; } @Override public String toString () { return "SuperUser{" + "address='" + address + '\'' + "} " + super .toString(); } }
单个 Bean 对象 集合 Bean 对象 1 2 3 4 5 6 7 private static void lookupByAnnotationType (BeanFactory beanFactory) { if (beanFactory instanceof ListableBeanFactory) { ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory; Map<String, User> users = (Map) listableBeanFactory.getBeansWithAnnotation(Super.class); System.out.println("查找标注 @Super 所有的 User 集合对象:" + users); } }
2. Spring IoC 依赖注入 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns:util ="http://www.springframework.org/schema/util" xsi:schemaLocation =" http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd" > <import resource ="dependency-lookup-context.xml" /> <bean id ="userRepositoryByName" class ="com.cruise.thinking.in.spring.ioc.container.overview.repository.UserRepositoryByName" autowire ="byName" /> <bean id ="userRepositoryByType" class ="com.cruise.thinking.in.spring.ioc.container.overview.repository.UserRepositoryByType" autowire ="byType" > </bean > <bean id ="repositoryByInnerBean" class ="com.cruise.thinking.in.spring.ioc.container.overview.repository.RepositoryByInnerBean" autowire ="byType" /> <bean id ="student" class ="com.cruise.thinking.in.spring.ioc.container.overview.domain.Student" scope ="prototype" /> <bean id ="repositoryLazy" class ="com.cruise.thinking.in.spring.ioc.container.overview.repository.RepositoryLazy" autowire ="byType" /> <bean id ="repositoryForBeanFactory" class ="com.cruise.thinking.in.spring.ioc.container.overview.repository.RepositoryForBeanFactory" autowire ="byType" /> </beans >
1 2 BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/dependency-injection-context.xml" );
根据 Bean 名称注入 用户仓库,演示通过名称注入属性user和superUser
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public class UserRepositoryByName { private User user; private User superUser; public User getUser () { return user; } public void setUser (User user) { this .user = user; } public User getSuperUser () { return superUser; } public void setSuperUser (User superUser) { this .superUser = superUser; } @Override public String toString () { return "UserRepositoryByName{" + "user=" + user + ", superUser=" + superUser + '}' ; } }
dependency-injection-context.xml
autowire = “byName”
1 2 3 4 <!-- 根据名称注入 --> <bean id="userRepositoryByName" class ="com.kesen.thinking.in.spring.ioc.container.overview.repository.UserRepositoryByName" autowire="byName" />
dependency-lookup-context.xml
1 2 3 4 5 6 7 8 9 10 <bean id ="user" class ="com.kesen.thinking.in.spring.ioc.container.overview.domain.User" > <property name ="id" value ="1" > </property > <property name ="name" value ="kesen" > </property > </bean > <bean id ="superUser" class ="com.kesen.thinking.in.spring.ioc.container.overview.domain.SuperUser" parent ="user" primary ="true" > <property name ="address" value ="Chengdu" > </property > </bean >
1 2 3 4 5 6 private static void injectionByName (BeanFactory beanFactory) { UserRepositoryByName repository = beanFactory.getBean(UserRepositoryByName.class); System.out.println("根据名称注入Bean:" + repository); }
根据 Bean 类型注入 User类型 是集合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public class UserRepositoryByType { private List<User> users; private SuperUser superUser; public List<User> getUsers () { return users; } public void setUsers (List<User> users) { this .users = users; } public SuperUser getSuperUser () { return superUser; } public void setSuperUser (SuperUser superUser) { this .superUser = superUser; } @Override public String toString () { return "UserRepositoryByType{" + "users=" + users + ", superUser=" + superUser + '}' ; } }
autowire = “byType”
1 2 3 4 5 6 7 8 9 10 11 <!-- 根据类型注入 --> <bean id="userRepositoryByType" class ="com.kesen.thinking.in.spring.ioc.container.overview.repository.UserRepositoryByType" autowire="byType" > <!--<property name="users" > <util:list> <ref bean="user" /> <ref bean="superUser" /> </util:list> </property>--> </bean>
单个 Bean 对象 1 2 3 4 private static void injectionByType (BeanFactory beanFactory) { UserRepositoryByType repository = beanFactory.getBean(UserRepositoryByType.class); System.out.println("根据类型注入单个Bean:" + repository.getSuperUser()); }
根据类型注入单个Bean:superUser{address=’Chengdu’} User{id=1, name=’kesen’}
集合 Bean 对象 1 2 3 4 5 private static void injectionByType (BeanFactory beanFactory) { UserRepositoryByType repository = beanFactory.getBean(UserRepositoryByType.class); System.out.println("根据类型注入单个Bean:" + repository.getSuperUser()); System.out.println("根据类型注入集合Bean:" + repository.getUsers()); }
根据类型注入单个Bean:superUser{address=’Chengdu’} User{id=1, name=’kesen’} 根据类型注入集合Bean:[User{id=1, name=’kesen’}, superUser{address=’Chengdu’} User{id=1, name=’kesen’}]
注入容器內建 Bean 对象 1 2 3 4 5 6 7 8 9 10 11 12 public class RepositoryByInnerBean { private Environment environment; public Environment getEnvironment () { return environment; } public void setEnvironment (Environment environment) { this .environment = environment; } }
1 2 3 4 <bean id ="repositoryByInnerBean" class ="com.kesen.thinking.in.spring.ioc.container.overview.repository.RepositoryByInnerBean" autowire ="byType" />
1 2 3 4 5 6 7 8 9 private static void injectionByInnerBean (BeanFactory beanFactory) { RepositoryByInnerBean repository = beanFactory.getBean(RepositoryByInnerBean.class); System.out.println("注入容器内建Bean:" + repository.getEnvironment()); }
注入非 Bean 对象 1 2 3 4 5 6 7 8 9 private static void injectionByNonBean (BeanFactory beanFactory) { try { BeanFactory factoryBean = beanFactory.getBean(BeanFactory.class); System.out.println("注入非Bean对象:" + factoryBean); } catch (NoSuchBeanDefinitionException e) { e.printStackTrace(); } }
注入类型 实时注入 延迟注入 1 2 3 4 5 6 7 8 9 10 11 12 public class RepositoryLazy { private ObjectFactory<Student> objectFactory; public ObjectFactory<Student> getObjectFactory () { return objectFactory; } public void setObjectFactory (ObjectFactory<Student> objectFactory) { this .objectFactory = objectFactory; } }
1 2 3 4 5 6 <bean id ="student" class ="com.kesen.thinking.in.spring.ioc.container.overview.domain.Student" scope ="prototype" /> <bean id ="repositoryLazy" class ="com.kesen.thinking.in.spring.ioc.container.overview.repository.RepositoryLazy" autowire ="byType" />
1 2 3 4 5 6 7 8 9 10 11 12 13 private static void injectionLazy (BeanFactory beanFactory) { RepositoryLazy repositoryLazy = beanFactory.getBean(RepositoryLazy.class); ObjectFactory<Student> objectFactory = repositoryLazy.getObjectFactory(); Student student = objectFactory.getObject(); System.out.println("延迟注入:" + student); }
3. Spring IoC 依赖来源 bean与非bean
自定义Bean 容器内建Bean对象 Environment
容器内建依赖 BeanFactory
4. Spring IoC 配置元信息 id/class
4.1 Bean 定义配置 基于 XML 文件 标签
基于 Properties 文件 基于 Java 注解 @Value
基于 Java API(专题讨论) BeanDifinition
4.2 IoC 容器配置 非核心的特性,
基于 XML 文件 基于 Java 注解 基于 Java API (专题讨论) 4.3 外部化属性配置 基于 Java 注解 5. Spring IoC 容器 BeanFactory
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public static void whoIsIoC () { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:/META-INF/dependency-injection-context.xml" ); RepositoryForBeanFactory repository = applicationContext.getBean(RepositoryForBeanFactory.class); BeanFactory beanFactory = repository.getBeanFactory(); System.out.println(beanFactory == applicationContext); System.out.println(beanFactory == applicationContext.getAutowireCapableBeanFactory()); }
6. Spring 应用上下文 ApplicationContext
ApplicationContext 除了 IoC 容器角色,还有提供:
面向切面(AOP)
配置元信息(Configuration Metadata)
资源管理(Resources)
事件(Events)
国际化(i18n)
注解(Annotations)
Environment 抽象(Environment Abstraction)
7. 使用 Spring IoC 容器 dependency-lookup-context.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <bean id ="user" class ="com.cruise.thinking.in.spring.ioc.container.overview.domain.User" > <property name ="id" value ="1" > </property > <property name ="name" value ="Cruise" > </property > </bean > <bean id ="objectFactory" class ="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean" > <property name ="targetBeanName" value ="user" > </property > </bean > <bean id ="superUser" class ="com.cruise.thinking.in.spring.ioc.container.overview.domain.SuperUser" parent ="user" primary ="true" > <property name ="address" value ="Beijing" > </property > </bean >
1、使用xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public static void beanFactoryAsIoCContainer () { DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory); int count = reader.loadBeanDefinitions("classpath:/META-INF/dependency-lookup-context.xml" ); System.out.println("加载的Bean数量" +count); User user = beanFactory.getBean(User.class); System.out.println("通过BeanFactory获取Bean:" +user); }
2、使用注解
1 2 3 4 5 6 7 @Bean public User user () { User user = new User(); user.setId(2L ); user.setName("Tom" ); return user; }
1 2 3 4 5 6 7 8 9 10 11 AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); applicationContext.register(AnnotationApplicationContextAsIoCContainerDemo.class); applicationContext.refresh(); lookupCollectionByType(applicationContext); applicationContext.close();
1 2 3 4 5 6 7 private static void lookupCollectionByType (BeanFactory beanFactory) { if (beanFactory instanceof ListableBeanFactory) { ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory; Map<String, User> users = listableBeanFactory.getBeansOfType(User.class); System.out.println("查找到的所有的 User 集合对象:" + users); } }
8. Spring IoC 容器生命周期 启动
运行
停止
9. 面试题 什么是 Spring IoC容器?
答:Spring Framework implementation of the Inversion of Control (IoC) principle.
IoC is also known as dependency injection (DI). It is a process whereby objects define their dependencies (that is, the other objects they work with) only through constructor arguments, arguments to a factory method, or properties that are set on the object instance after it is constructed or returned from a factory method. The container then injects those dependencies when it creates the bean
BeanFactory 与 FactoryBean?
答: BeanFactory 是 IoC 底层容器 FactoryBean 是 创建 Bean 的一种方式,帮助实现复杂的初始化逻辑
Spring IoC 容器启动时做了哪些准备?
答:IoC 配置元信息读取和解析、IoC 容器生命周期、Spring 事件发布、 国际化等