IOC的两种实现方式:依赖查找(DL)和依赖注入(DI)。
DI和DL的区别在于依赖的对象是否为主动获取,是的话,就是依赖查找,否则就是依赖注入,由框架绑定完成。如下面例子中的UserRepository,两者在main函数中没有区别,都是通过Context上下文API实现的;
依赖查找的例子
dependency-lookup-context.xml
<?xml version="1.0" encoding="UTF-8"?><beansxmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsd"><!-- <context:annotation-config/>--><!-- <context:component-scan base-package="org.acme" />--><!-- Root BeanDefinition 不需要合并,不存在 parent --><!-- 普通 beanDefinition GenericBeanDefinition --><!-- 经过合并后 GenericBeanDefinition 变成 RootBeanDefinition --><bean id="user" class="org.geekbang.thinking.in.spring.ioc.overview.domain.User"><property name="id" value="1"/><property name="name" value="小马哥"/><property name="city" value="HANGZHOU"/><property name="workCities" value="BEIJING,HANGZHOU"/><property name="lifeCities"><list><value>BEIJING</value><value>SHANGHAI</value></list></property><property name="configFileLocation" value="classpath:/META-INF/user-config.properties"/></bean><!-- 普通 beanDefinition GenericBeanDefinition --><!-- 合并后 GenericBeanDefinition 变成 RootBeanDefinition,并且覆盖 parent 相关配置--><!-- primary = true , 增加了一个 address 属性 --><bean id="superUser" class="org.geekbang.thinking.in.spring.ioc.overview.domain.SuperUser" parent="user"primary="true"><property name="address" value="杭州"/></bean><bean id="objectFactory" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean"><property name="targetBeanName" value="user"/></bean></beans>
User
public class User implements BeanNameAware {private Long id;private String name;private City city;private City[] workCities;private List<City> lifeCities;private Resource configFileLocation;private Company company;private Properties context;private String contextAsText;/*** 当前 Bean 的名称*/private transient String beanName;public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public City getCity() {return city;}public void setCity(City city) {this.city = city;}public Resource getConfigFileLocation() {return configFileLocation;}public void setConfigFileLocation(Resource configFileLocation) {this.configFileLocation = configFileLocation;}public City[] getWorkCities() {return workCities;}public void setWorkCities(City[] workCities) {this.workCities = workCities;}public List<City> getLifeCities() {return lifeCities;}public void setLifeCities(List<City> lifeCities) {this.lifeCities = lifeCities;}public Company getCompany() {return company;}public void setCompany(Company company) {this.company = company;}public static User createUser() {User user = new User();user.setId(1L);user.setName("小马哥");return user;}@PostConstructpublic void init() {System.out.println("User Bean [" + beanName + "] 初始化...");}@PreDestroypublic void destroy() {System.out.println("User Bean [" + beanName + "] 销毁中...");}@Overridepublic void setBeanName(String name) {this.beanName = name;}public Properties getContext() {return context;}public void setContext(Properties context) {this.context = context;}public String getContextAsText() {return contextAsText;}public void setContextAsText(String contextAsText) {this.contextAsText = contextAsText;}@Overridepublic String toString() {return "User{" +"id=" + id +", name='" + name + '\'' +", city=" + city +", workCities=" + Arrays.toString(workCities) +", lifeCities=" + lifeCities +", configFileLocation=" + configFileLocation +", company=" + company +", context=" + context +", contextAsText='" + contextAsText + '\'' +", beanName='" + beanName + '\'' +'}';}
SuperUser
@Superpublic class SuperUser extends User {private String address;public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}@Overridepublic String toString() {return "SuperUser{" +"address='" + address + '\'' +"} " + super.toString();}}
public static void main(String[] args) {// 配置 XML 配置文件// 启动 Spring 应用上下文BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/dependency-lookup-context.xml");// 按照类型查找lookupByType(beanFactory);// 按照类型查找结合对象lookupCollectionByType(beanFactory);// 通过注解查找对象lookupByAnnotationType(beanFactory);// lookupInRealTime(beanFactory);// lookupInLazy(beanFactory);}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);}}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);}}private static void lookupByType(BeanFactory beanFactory) {User user = beanFactory.getBean(User.class);System.out.println("实时查找:" + user);}private static void lookupInLazy(BeanFactory beanFactory) {ObjectFactory<User> objectFactory = (ObjectFactory<User>) beanFactory.getBean("objectFactory");User user = objectFactory.getObject();System.out.println("延迟查找:" + user);}private static void lookupInRealTime(BeanFactory beanFactory) {User user = (User) beanFactory.getBean("user");System.out.println("实时查找:" + user);}
依赖注入的例子
dependency-injection-context.xml
<?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.xsdhttp://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd"><!-- 通过导入复用 dependency-lookup-context.xml --><import resource="dependency-lookup-context.xml"/><bean id="userRepository" class="org.geekbang.thinking.in.spring.ioc.overview.repository.UserRepository"autowire="byType"> <!-- Auto-Wiring --><!-- 手动配置 --><!-- <property name="users">--><!-- <util:list>--><!-- <ref bean="superUser" />--><!-- <ref bean="user" />--><!-- </util:list>--><!-- </property>--></bean></beans>
UserRepository
public class UserRepository {private Collection<User> users; // 自定义 Beanprivate BeanFactory beanFactory; // 內建非 Bean 对象(依赖)private ObjectFactory<ApplicationContext> objectFactory;public Collection<User> getUsers() {return users;}public void setUsers(Collection<User> users) {this.users = users;}public void setBeanFactory(BeanFactory beanFactory) {this.beanFactory = beanFactory;}public BeanFactory getBeanFactory() {return beanFactory;}public ObjectFactory<ApplicationContext> getObjectFactory() {return objectFactory;}public void setObjectFactory(ObjectFactory<ApplicationContext> objectFactory) {this.objectFactory = objectFactory;}}
public static void main(String[] args) {// 配置 XML 配置文件// 启动 Spring 应用上下文// BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/dependency-injection-context.xml");ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:/META-INF/dependency-injection-context.xml");// 依赖来源一:自定义 BeanUserRepository userRepository = applicationContext.getBean("userRepository", UserRepository.class);// System.out.println(userRepository.getUsers());// 依赖来源二:依赖注入(內建依赖)System.out.println(userRepository.getBeanFactory());ObjectFactory userFactory = userRepository.getObjectFactory();System.out.println(userFactory.getObject() == applicationContext);// 依赖查找(错误)// System.out.println(beanFactory.getBean(BeanFactory.class));// 依赖来源三:容器內建 BeanEnvironment environment = applicationContext.getBean(Environment.class);System.out.println("获取 Environment 类型的 Bean:" + environment);}private static void whoIsIoCContainer(UserRepository userRepository, ApplicationContext applicationContext) {// ConfigurableApplicationContext <- ApplicationContext <- BeanFactory// ConfigurableApplicationContext#getBeanFactory()// 这个表达式为什么不会成立System.out.println(userRepository.getBeanFactory() == applicationContext);// ApplicationContext is BeanFactory}
