本文内容如有错误、不足之处,欢迎技术爱好者们一同探讨,在本文下面讨论区留言,感谢。欢迎转载,转载请注明出处(https://blog.csdn.net/feng_xiaoshi/article/details/105799771),谢谢。
简介
依赖注入主要有两种模式,手动模式和自动模式,自动模式又叫做 Autowiring(自动绑定),官方不推荐使用自动模式。
手动模式
通过配置或者编程的方式,提前安排注入规则:
- XML 资源配置元信息
- Java 注解配置元信息
- API 配置元信息
通常开发过程中较常使用的是 XML配置和 Java 注解配置,API配置不常使用,API配置通常是给容器开发者或者Spring扩展使用。
事实上 XML 配置和 Java 注解配置就依赖于 API 配置的操作。
自动模式
实现方提供依赖自动关联的方式,按照内建的注入规则,专业术语叫 Autowiring ,Spring 容器能够通过自动绑定的关系,在合作 Bean 之间(依赖类和被依赖类)将 Bean 和 Bean 之间的相互依赖关系(组合或关联),处理和合作者的关系。这里的合作者不一定是 Bean ,也可能是资源。Autowiring 可以减少参数或者构造器配置参数。
自动模式的几种类型
类型 | 说明 |
---|---|
no | 默认值,未激活,需要手动指定依赖注入对象 |
byName | 根据被注入属性的名称作为 Bean 名称进行依赖查找,并将对象设置到该属性 |
byType | 根据被注入属性的类型作为依赖类型进行查找,并将对象设置到该属性 |
constructor | 特殊的 byType 类型,用于构造器参数 |
Spring 中 Autowire 枚举就是上面集大成者:
public enum Autowire {
/**
* Constant that indicates no autowiring at all.
*/
NO(AutowireCapableBeanFactory.AUTOWIRE_NO),
/**
* Constant that indicates autowiring bean properties by name.
*/
BY_NAME(AutowireCapableBeanFactory.AUTOWIRE_BY_NAME),
/**
* Constant that indicates autowiring bean properties by type.
*/
BY_TYPE(AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE);
// 这里为什么没有出现构造器呢! 因为它是特殊的 byType
private final int value;
Autowire(int value) {
this.value = value;
}
public int value() {
return this.value;
}
/**
* Return whether this represents an actual autowiring value.
* @return whether actual autowiring was specified
* (either BY_NAME or BY_TYPE)
*/
public boolean isAutowire() {
return (this == BY_NAME || this == BY_TYPE);
}
}
Autowire引用了 AutowireCapableBeanFactory 类,具有自动绑定功能的 BeanFactory,通过名字就可以判断出继承了 BeanFactory。
public interface AutowireCapableBeanFactory extends BeanFactory {
int AUTOWIRE_NO = 0;
int AUTOWIRE_BY_NAME = 1;
int AUTOWIRE_BY_TYPE = 2;
int AUTOWIRE_CONSTRUCTOR = 3;
// 自动探测 Spring 3 以前遗留的
@Deprecated
int AUTOWIRE_AUTODETECT = 4;
String ORIGINAL_INSTANCE_SUFFIX = ".ORIGINAL";
<T> T createBean(Class<T> beanClass) throws BeansException;
void autowireBean(Object existingBean) throws BeansException;
Object configureBean(Object existingBean, String beanName) throws BeansException;
Object createBean(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
Object autowire(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
void autowireBeanProperties(Object existingBean, int autowireMode, boolean dependencyCheck)
throws BeansException;
void applyBeanPropertyValues(Object existingBean, String beanName) throws BeansException;
Object initializeBean(Object existingBean, String beanName) throws BeansException;
Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException;
Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException;
void destroyBean(Object existingBean);
<T> NamedBeanHolder<T> resolveNamedBean(Class<T> requiredType) throws BeansException;
Object resolveBeanByName(String name, DependencyDescriptor descriptor) throws BeansException;
@Nullable
Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName) throws BeansException;
@Nullable
Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException;
}
自动配置的缺陷
自动配置是一种猜测性的技术,或者说是半猜测的技术,通过关联,容器会根据名称、类型、构造方法进行查找相同的进行一个关联,因此就会产生一个问题:Spring 会非常关注这个查找的精确性,如果出现一些模糊的情况,比如说名称取得不对,这样就会出现一个不确定的结果。
依赖注入类型
依赖注入类型 | 配置元数据 |
---|---|
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{…} |
Setter 方法通过方法注入,构造器通过构造器参数来进行传递,字段注入在 XML 配置中没有方法可以实现,Setter 注入是通过一个 Set 方法来实现参数绑定或者关联到数据,XML 配置是通过调用 Set 方法,通过反射的方式来进行调用,字段注入是直接把这个参数注入到字段,其实 Spring 官方是不想采纳这种实现方式。接口回调通过显示的传递 BeanFactory 给你的接口进行回调。
Autowire 是通过静态上下文绑定,因为在动态上下文中,Spring 很难判断Bean 是不是已经在上下文中,无法确保整个 classpath 上所有的包是不是都少建了,由于没有运行状态因此无法进行预判。
总结
在本文中,通过依赖注入的模式和类型方面,讨论了不同注入的不同点和相同点。以及使用自动注入时需要注意的地方。
参考资料
Spring 依赖注入(DI) 的三种方式 和 对集合类型的注入
spring的IOC——依赖注入的两种实现类型