注:以下内容为学习《小马哥讲Spring核心编程思想》的个人笔记
Setter方法依赖注入
手动模式
-
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" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <!--通过xml的配置方式注入--> <bean class="org.geekbang.thinking.in.spring.ioc.dependency.injection.UserHolder"> <property name="user" ref="superUser" /> </bean> </beans>
-
Java 注解配置元信息
// 通过注解的方式注入 @Bean public UserHolder userHolder(User user) { UserHolder userHolder = new UserHolder(); userHolder.setUser(user); return userHolder; }
-
API 配置元信息
// 通过Api形式 private static BeanDefinition createUserHolderBeanDefinition() { BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserHolder.class); definitionBuilder.addPropertyReference("user", "superUser"); return definitionBuilder.getBeanDefinition(); }
实际上,不管是什么形式注入,实际上最后生成的是BeanDefinition,spring通过解析BeanDefinition来创建Bean。因此,Java注解,api配置和xml配置实际上是对BeanDefinition属性的补充
自动模式
不建议使用自动模式,不可控
-
byName
<bean class="org.geekbang.thinking.in.spring.ioc.dependency.injection.UserHolder" autowire="byName" > <!-- <property name="user" ref="superUser" /> 替换成 autowiring 模式 --> </bean>
-
byType
<bean class="org.geekbang.thinking.in.spring.ioc.dependency.injection.UserHolder" autowire="byType" > <!-- <property name="user" ref="superUser" /> 替换成 autowiring 模式 --> </bean>
构造器依赖注入
手动模式
-
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" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <import resource="classpath:/"/> <bean class="org.geekbang.thinking.in.spring.ioc.dependency.injection.UserHolder"> <constructor-arg name="user" ref="superUser" /> </bean> </beans>
-
Java 注解配置元信息
@Bean public UserHolder userHolder(User user) { // 与setter不同的是直接通过构造方法传入Bean return new UserHolder(user); }
-
API 配置元信息
/** * 为 {@link UserHolder} 生成 {@link BeanDefinition} * * @return */ private static BeanDefinition createUserHolderBeanDefinition() { BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserHolder.class); definitionBuilder.addConstructorArgReference("superUser"); return definitionBuilder.getBeanDefinition(); }
自动模式
不建议使用自动模式,不可控
-
constructor
<bean class="org.geekbang.thinking.in.spring.ioc.dependency.injection.UserHolder" autowire="constructor"> <!-- <property name="user" ref="superUser" /> 替换成 autowiring 模式 --> </bean>
字段注入
注解在字段上面
手动模式
- Java 注解配置元信息
-
@Autowired
-
@Resource
-
@Inject(可选)
-
@Autowired
private UserHolder userHolder;
@Resource
private UserHolder userHolder2;
方法注入
注解在方法上面
手动模式
Java 注解配置元信息
-
@Autowired
-
@Resource
-
@Inject(可选)
-
@Bean
@Autowired
public void init1(UserHolder userHolder) {
this.userHolder = userHolder;
}
@Resource
public void init2(UserHolder userHolder2) {
this.userHolder2 = userHolder2;
}
@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 对象,用于占位符处理 |
依赖注入类型选择
注入选型
- 低依赖:构造器注入
- 多依赖: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
限定注入
使用注解 @Qualifier 限定
@Configuration
public class QualifierAnnotationDependencyInjectionDemo {
// 通过名称限定
@Autowired
@Qualifier("user1")
private User namedUser;
// 不限定
@Autowired
private Collection<User> allUsers;
// 分组限定
@Autowired
@Qualifier
private Collection<User> qualifiedUsers;
// 自定义注解限定
@Autowired
@UserGroup
private Collection<User> groupedUsers;
@Bean
@Qualifier // 进行逻辑分组
public User user1() {
return createUser(7L);
}
@Bean
@Qualifier // 进行逻辑分组
public User user2() {
return createUser(8L);
}
@Bean
@UserGroup
public User user3() {
return createUser(9L);
}
@Bean
@UserGroup
public User user4() {
return createUser(10L);
}
private static User createUser(Long id) {
User user = new User();
user.setId(id);
return user;
}
}
-
通过 Bean 名称限定
// 通过名称限定,namedUser注入的Bean是user1 @Autowired @Qualifier("user1") private User namedUser;
-
通过分组限定
// 分组限定,qualifiedUsers注入的是user1,user2,user3,user4。@UserGroup注解扩展了@Qualifier @Autowired @Qualifier private Collection<User> qualifiedUsers;
基于注解 @Qualifier 扩展限定
-
自定义注解 - 如 Spring Cloud @LoadBalanced
// 自定义注解限定,groupedUsers注入的是user3,user4。自定义的 @UserGroup 注解 @Autowired @UserGroup private Collection<User> groupedUsers;
延迟依赖注入
使用 API ObjectFactory 延迟注入
- 单一类型
- 集合类型
使用 API ObjectProvider 延迟注入(推荐)
-
单一类型
-
集合类型
@Autowired private ObjectProvider<User> userObjectProvider; // 延迟注入 @Autowired private ObjectFactory<Set<User>> usersObjectFactory;
依赖处理过程
基础知识
-
入口 - DefaultListableBeanFactory#resolveDependency
-
依赖描述符 - DependencyDescriptor
public class DependencyDescriptor extends InjectionPoint implements Serializable { // 要被注入的类 private final Class<?> declaringClass; // 方法注入的方法名 @Nullable private String methodName; // 构造器注入的参数列表 @Nullable private Class<?>[] parameterTypes; private int parameterIndex; // 字段注入的字段名 @Nullable private String fieldName; // 参考@Autowire里面required private final boolean required; // 是否是懒加载 private final boolean eager; private int nestingLevel = 1; @Nullable private Class<?> containingClass; @Nullable private transient volatile ResolvableType resolvableType; @Nullable private transient volatile TypeDescriptor typeDescriptor; }
-
自定绑定候选对象处理器 - AutowireCandidateResolver
@Autowired注入原理
@Autowired 注入的步骤在org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessProperties方法中,该方法在 org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor 接口中定义。
- 元信息解析
- 依赖查找
- 依赖注入(字段、方法)
//org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
if (this.cached) {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
else {
// 获取依赖描述符
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
Assert.state(beanFactory != null, "No BeanFactory available");
TypeConverter typeConverter = beanFactory.getTypeConverter();
try {
// 查找对应的依赖
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
synchronized (this) {
if (!this.cached) {
if (value != null || this.required) {
this.cachedFieldValue = desc;
registerDependentBeans(beanName, autowiredBeanNames);
if (autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
this.cachedFieldValue = new ShortcutDependencyDescriptor(
desc, autowiredBeanName, field.getType());
}
}
}
else {
this.cachedFieldValue = null;
}
this.cached = true;
}
}
}
// 通过反射进行注入
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
}
JSR-330 @Inject注入原理
@Inject 注入过程
如果 JSR-330 存在于 ClassPath 中,复用 AutowiredAnnotationBeanPostProcessor 实现
//org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#AutowiredAnnotationBeanPostProcessor
public AutowiredAnnotationBeanPostProcessor() {
this.autowiredAnnotationTypes.add(Autowired.class);
this.autowiredAnnotationTypes.add(Value.class);
try {
// 判断加载Inject注解,如果不存在,则不加载
this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
Java通用注解注入注解
@Autowired 注入的步骤在org.springframework.beans.factory.annotation.CommonAnnotationBeanPostProcessor#postProcessProperties方法中,该方法在 org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor 接口中定义。
注入注解
- javax.xml.ws.WebServiceRef
- javax.ejb.EJB
- javax.annotation.Resource
生命周期注解
- javax.annotation.PostConstruct
- javax.annotation.PreDestroy
自定义依赖注入注解
有用的广告
我是程序员,也热爱投资。个人认为,程序员这种职业(大部分是青春饭)非常适合投资,在年轻的积累本金,35岁后能过有睡后收入,想想就美滋滋。当然,如果没有专业的投资知识就是在股市中韭菜的份,这里推广下我学习投资知识的地方。简单说明下,这两个群都不会荐股,只是告诉你投资理念和知识,授人以鱼不如授人以渔,如果对投资感兴趣的人,我相信你会觉得相见恨晚。
老齐的读书圈:里面包含了几百本书籍,主要包括投资类,格局类,经营管理类三种。感兴趣的可以听听,三天内无条件可以退款。强烈推荐
齐俊杰的粉丝群:主要是对市场的解读,当然里面主要考虑的是周期的定位以及资产配置的相关知识。感兴趣的也可以进来听听,