依赖注入的模式和类型
• 手动模式 - 配置或者编程的方式,提前安排注入规则
- XML 资源配置元信息
- Java 注解配置元信息
- API 配置元信息
• 自动模式 - 实现方提供依赖自动关联的方式,按照內建的注入规则
- Autowiring(自动绑定)
依赖注入类型
依赖注入类型 | 配置元数据举例 |
---|---|
Setter 方法 | <proeprty name=“user” ref=“userBean”/> |
构造器 | <constructor-arg name=“user” ref=“userBean” /> |
字段 | @Autowired User user; |
方法 | @Autowired public void user(User user) { … } |
接口回调 | class MyBean implements BeanFactoryAware { … } |
自动绑定(Autowiring)
官方说明
The Spring container can autowire relationships between collaborating beans. You can let Spring resolve collaborators (other beans) automatically for your bean by inspecting the contents of the ApplicationContext.
优点
• Autowiring can significantly reduce the need to specify properties or constructor arguments.
• Autowiring can update a configuration as your objects evolve.
自动绑定(Autowiring)模式
Autowiring modes
模式 | 说明 |
---|---|
no | 默认值,未激活 Autowiring,需要手动指定依赖注入对象。 |
byName | 根据被注入属性的名称作为 Bean 名称进行依赖查找,并将对象设置到该属性。 |
byType | 根据被注入属性的类型作为依赖类型进行查找,并将对象设置到该属性。 |
constructor | 特殊 byType 类型,用于构造器参数。 |
自动绑定(Autowiring)限制和不足
官方说明
Limitations and Disadvantages of Autowiring 小节
链接:https://docs.spring.io/spring/docs/5.2.2.RELEASE/spring-framework-reference/core.html#beans-autowired-exceptions
Setter 方法注入
实现方法
• 手动模式
- XML 资源配置元信息
- Java 注解配置元信息
- API 配置元信息
• 自动模式
- byName
- byType
/**
* 基于 API 实现依赖 Setter 方法注入示例
*/
public class ApiDependencySetterInjectionDemo {
public static void main(String[] args) {
// 创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 生成 UserHolder 的 BeanDefinition
BeanDefinition userHolderBeanDefinition = createUserHolderBeanDefinition();
// 注册 UserHolder 的 BeanDefinition
applicationContext.registerBeanDefinition("userHolder", userHolderBeanDefinition);
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
// 加载 XML 资源,解析并且生成 BeanDefinition
beanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
// 启动 Spring 应用上下文
applicationContext.refresh();
// 依赖查找并且创建 Bean
UserHolder userHolder = applicationContext.getBean(UserHolder.class);
System.out.println(userHolder);
// 显示地关闭 Spring 应用上下文
applicationContext.close();
}
/**
* 为 {@link UserHolder} 生成 {@link BeanDefinition}
*/
private static BeanDefinition createUserHolderBeanDefinition() {
BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserHolder.class);
definitionBuilder.addPropertyReference("user", "superUser");
return definitionBuilder.getBeanDefinition();
}
}
构造器注入
实现方法
• 手动模式
- XML 资源配置元信息
- Java 注解配置元信息
- API 配置元信息
• 自动模式
- constructor
/**
* 基于 API 实现依赖 Constructor 注入示例
*/
private static BeanDefinition createUserHolderBeanDefinition() {
BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserHolder.class);
definitionBuilder.addConstructorArgReference("superUser");
return definitionBuilder.getBeanDefinition();
}
字段注入
实现方法
• 手动模式
- Java 注解配置元信息
• @Autowired
• @Resource
• @Inject(可选)
// @Autowired 会忽略掉static静态字段
@Autowired
private UserHolder userHolder;
@Resource
private UserHolder userHolder2;
方法注入
• 手动模式
- Java 注解配置元信息
• @Autowired
• @Resource
• @Inject(可选)
• @Bean
@Autowired
public void init1(UserHolder userHolder) {
this.userHolder = userHolder;
}
@Bean
public UserHolder userHolder(User user) {
return new UserHolder(user);
}
接口回调注入
Aware 系列接口回调
• 自动模式
內建接口 | 说明 |
---|---|
BeanFactoryAware | 获取 IoC 容器 - BeanFactory |
ApplicationContextAware | 获取 Spring 应用上下文 - ApplicationContext 对象 |
EnvironmentAware | 获取 Environment 对象 |
ResourceLoaderAware | 获取资源加载器 对象 - ResourceLoader |
BeanClassLoaderAware | 获取加载当前 Bean Class 的 ClassLoader |
BeanNameAware | 获取当前 Bean 的名称 |
MessageSourceAware | 获取 MessageSource 对象,用于 Spring 国际化 |
ApplicationEventPublisherAware | 获取 ApplicationEventPublishAware 对象,用于 Spring 事件 |
EmbeddedValueResolverAware | 获取 StringValueResolver 对象,用于占位符处理 |
public class AwareInterfaceDependencyInjectionDemo implements BeanFactoryAware, ApplicationContextAware {
private static BeanFactory beanFactory;
private static ApplicationContext applicationContext;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
AwareInterfaceDependencyInjectionDemo.beanFactory = beanFactory;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
AwareInterfaceDependencyInjectionDemo.applicationContext = applicationContext;
}
}
依赖注入类型选择
注入选型
• 低依赖:构造器注入
• 多依赖:Setter 方法注入
• 便利性:字段注入
• 声明类:方法注入
基础类型注入
基础类型
• 原生类型(Primitive):boolean、byte、char、short、int、float、long、double
• 标量类型(Scalar):Number、Character、Boolean、Enum、Locale、Charset、Currency、Properties、UUID
• 常规类型(General):Object、String、TimeZone、Calendar、Optional 等
• Spring 类型:Resource、InputSource、Formatter 等
集合类型注入
集合类型
• 数组类型(Array):原生类型、标量类型、常规类型、Spring 类型
• 集合类型(Collection)
- Collection:List、Set(SortedSet、NavigableSet、EnumSet)
- Map:Properties
<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>
限定注入
• 使用注解 @Qualifier 限定
- 通过 Bean 名称限定
- 通过分组限定
• 基于注解 @Qualifier 扩展限定
- 自定义注解 - 如 Spring Cloud @LoadBalanced
@Autowired
private User user; // superUser -> primary =true
@Autowired
@Qualifier("user") // 指定 Bean 名称或 ID
private User namedUser;
// 整体应用上下文存在 4 个 User 类型的 Bean:
// superUser
// user
// user1 -> @Qualifier
// user2 -> @Qualifier
@Autowired
private Collection<User> allUsers; // 2 Beans = user + superUser
@Autowired
@Qualifier
private Collection<User> qualifiedUsers; // 2 Beans = user1 + user2 -> 4 Beans = user1 + user2 + user3 + user4
@Autowired
@UserGroup
private Collection<User> groupedUsers; // 2 Beans = user3 + user4
@Bean
@Qualifier // 进行逻辑分组
public User user1() {
return createUser(7L);
}
@Bean
@Qualifier // 进行逻辑分组
public static User user2() {
return createUser(8L);
}
@Bean
@UserGroup
public static User user3() {
return createUser(9L);
}
@Bean
@UserGroup
public static User user4() {
return createUser(10L);
}
延迟依赖注入
• 使用 API ObjectFactory 延迟注入
- 单一类型
- 集合类型
• 使用 API ObjectProvider 延迟注入(推荐)
- 单一类型
- 集合类型
@Autowired
@Qualifier("user")
private User user; // 实时注入
@Autowired
private ObjectProvider<User> userObjectProvider; // 延迟注入
@Autowired
private ObjectFactory<Set<User>> usersObjectFactory;
@Autowired
@Lazy
@Qualifier("user")
private User user;
依赖处理过程
• 入口 - DefaultListableBeanFactory#resolveDependency
• 依赖描述符 - DependencyDescriptor
• 自定绑定候选对象处理器 - AutowireCandidateResolver
@Autowired 注入
@Autowired 注入规则
• 非静态字段
• 非静态方法
• 构造器
@Autowired 注入过程
• 元信息解析
• 依赖查找
• 依赖注入(字段、方法)
@Inject 注入
@Inject 注入过程
• 如果 JSR-330 存在于 ClassPath 中,复用 AutowiredAnnotationBeanPostProcessor 实现
Java通用注解注入原理
CommonAnnotationBeanPostProcessor
• 注入注解
- javax.xml.ws.WebServiceRef
- javax.ejb.EJB
- javax.annotation.Resource
• 生命周期注解
- javax.annotation.PostConstruct
- javax.annotation.PreDestroy
自定义依赖注入注解
• 基于 AutowiredAnnotationBeanPostProcessor 实现
• 自定义实现
-
生命周期处理
• InstantiationAwareBeanPostProcessor
• MergedBeanDefinitionPostProcessor -
元数据
• InjectedElement
• InjectionMetadata
@Bean
@Order(Ordered.LOWEST_PRECEDENCE - 3)
@Scope
public static AutowiredAnnotationBeanPostProcessor beanPostProcessor() {
AutowiredAnnotationBeanPostProcessor beanPostProcessor = new AutowiredAnnotationBeanPostProcessor();
beanPostProcessor.setAutowiredAnnotationType(InjectedUser.class);
return beanPostProcessor;
}
面试题
有多少种依赖注入的方式?
答:构造器注入、Setter 注入、字段注入、方法注入、接口回调注入
你偏好构造器注入还是 Setter 注入?
答:两种依赖注入的方式均可使用,如果是必须依赖的话,那么推荐使用构造器注入,Setter 注入用于可选依赖。