文章目录
- 一、依赖查找
- 1、单一类型依赖查找(接口 - BeanFactory)
- 根据Bean名称查找
- 根据Bean类型实时查找
- 根据Bean类型延迟查找(Spring 5.1)
- 根据Bean名称+类型查找
- 2、集合类型依赖查找(接口 - ListableBeanFactory)
- 根据Bean类型查找
- 通过注解类型查找 Spring 4.0
- 3、层次性依赖查找(接口 - HierarchicalBeanFactory)
- 层次性容器使用场景
- 层次性依赖查找实例
- 使用BeanFactoryUtils查找Bean
- 4、延迟依赖查找(接口 - ObjectFactory)
- 理解什么是延迟依赖查找
- 熟悉ObjectFactory的子接口-ObjectProvider接口
- 延迟加载ObjectProvider使用示例
- 5、依赖查找的异常安全性
- 安全依赖查找代码实例
- 由依赖查找的异常安全性做出的总结
- 6、Spring内建可查找的依赖
- AbstractApplicationContext 内建可查找的依赖
- 注解驱动 Spring 应用上下文内建可查找的依赖
- 7、依赖查找中的经典异常
- 附1:各个BeanFactory的继承关系
- 附2:ApplicationContext继承关系
- 二、依赖注入
- 1、自动绑定(Autowiring-区别于@Autowired)
- 2、Setter 方法注入
- 自动Setter注入
- 手动Setter注入
- 3、构造器注入(官方推荐)
- 自动构造器注入
- 手动构造器注入
- 4、字段注入
- 5、方法注入
- 6、接口回调注入
- 7、各种依赖注入比较
- 8、基础类型的注入
- 9、集合类型注入
- 10、限定注入
- 使用注解 @Qualifier 通过Bean 名称限定
- 使用注解 @Qualifier 通过分组限定
- 基于注解 @Qualifier 扩展限定
- 案例
- 11、延迟依赖注入
- 12、Optional类型注入
- 13、依赖注入处理的过程源码分析
- 14、详解@Autowired 注入
- 15、JSR-330 @Inject 注入
- 16、Java通用注解注入原理
- 17、自定义依赖注入注解
- 基于@Autowired元注解创建自定义注解
- 基于 AutowiredAnnotationBeanPostProcessor 实现
- 自定义实现(略)
- 19、附:关于加static的bean会提前注册问题
一、依赖查找
1、单一类型依赖查找(接口 - BeanFactory)
用于查找已知类型或名称的Bean对象。
根据Bean名称查找
// getBean(String) 根据名称获取bean
Object bean = beanfactory.getBean("beanName");
// Spring 2.5 覆盖默认参数:getBean(String,Object...)
Object bean = beanfactory.getBean("beanName", args ...);
根据Bean类型实时查找
// Spring 3.0 getBean(Class)
User bean = beanfactory.getBean(User.class);
// Spring 4.1 覆盖默认参数:getBean(Class,Object...)
User bean = beanfactory.getBean(User.class, args ...);
根据Bean类型延迟查找(Spring 5.1)
// getBeanProvider(Class)
ObjectProvider<User> objectProvider = applicationContext.getBeanProvider(User.class);
User bean = beanfactory.getObject();
// getBeanProvider(ResolvableType)
根据Bean名称+类型查找
// getBean(String,Class)
User bean = beanfactory.getBean("beanName", User.class);
2、集合类型依赖查找(接口 - ListableBeanFactory)
查找已知类型多个Bean的集合。
ListableBeanFactory接口继承了BeanFactory接口,在原来的BeanFactory接口的基础上做了增强。
对于集合类型依赖查找,通过ListableBeanFactory#getBeanNamesForType 和ListableBeanFactory#getBeansForType,两个依赖查找方法,前者不会强制bean的初始化,而是通过BeanDefinition和FactoryBean的getClassType进行判断;后者会强制Bean的初始化。
根据Bean类型查找
// 获取同类型 Bean 名称列表 getBeanNamesForType(Class)
String[] beans = factory.getBeanNamesForType(User.class);
// 获取同类型 Bean 名称列表 Spring 4.2
getBeanNamesForType(ResolvableType)
// 获取同类型 Bean 实例列表 getBeansOfType(Class) 以及重载方法
Map<String, User> usersMap = context.getBeansOfType(User.class);
通过注解类型查找 Spring 4.0
可以查找到标注了某注解的bean。
// 获取标注类型 Bean 名称列表
getBeanNamesForAnnotation(Class<? extends Annotation>)
// 获取标注类型 Bean 实例列表
getBeansWithAnnotation(Class<? extends Annotation>)
// 获取指定名称 + 标注类型 Bean 实例
findAnnotationOnBean(String,Class<? extends Annotation>)
3、层次性依赖查找(接口 - HierarchicalBeanFactory)
层次性容器使用场景
容器的层次关系主要的目的是实现 Bean 复用,假设一个应用存在一个 Root ApplicationContext,内部的 Bean 来自于一个 jar 包,那么,这个jar 包可能被两个不同的 Servlet 应用使用,这时,ServletContext A 和 ServletContext B 同时复用了这个 parent ApplicationContext,而它自己也有 ApplicationContext,这也是 Spring Web MVC 所涉及的应用上下文架构。
层次性依赖查找实例
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.HierarchicalBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* 层次性依赖查找示例
*/
public class HierarchicalDependencyLookupDemo {
public static void main(String[] args) {
// 创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 将当前类 ObjectProviderDemo 作为配置类(Configuration Class)
applicationContext.register(ObjectProviderDemo.class); // 不包含user
// 1. 获取 HierarchicalBeanFactory <- ConfigurableBeanFactory(子) <- ConfigurableListableBeanFactory(子)
ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
// System.out.println("当前 BeanFactory 的 Parent BeanFactory : " + beanFactory.getParentBeanFactory());
// 2. 设置 Parent BeanFactory
HierarchicalBeanFactory parentBeanFactory = createParentBeanFactory(); // 包含user
beanFactory.setParentBeanFactory(parentBeanFactory);
// System.out.println("当前 BeanFactory 的 Parent BeanFactory : " + beanFactory.getParentBeanFactory());
// 查询LocalBean
displayContainsLocalBean(beanFactory, "user");
displayContainsLocalBean(parentBeanFactory, "user");
// 通过递归查询Bean
displayContainsBean(beanFactory, "user");
displayContainsBean(parentBeanFactory, "user");
// 启动应用上下文
applicationContext.refresh();
// 关闭应用上下文
applicationContext.close();
}
private static void displayContainsBean(HierarchicalBeanFactory beanFactory, String beanName) {
System.out.printf("当前 BeanFactory[%s] 是否包含 Bean[name : %s] : %s\n", beanFactory, beanName,
containsBean(beanFactory, beanName));
}
/**
* 双亲委派方式,优先查找父类的Bean
*/
private static boolean containsBean(HierarchicalBeanFactory beanFactory, String beanName) {
BeanFactory parentBeanFactory = beanFactory.getParentBeanFactory();
if (parentBeanFactory instanceof HierarchicalBeanFactory) {
HierarchicalBeanFactory parentHierarchicalBeanFactory = HierarchicalBeanFactory.class.cast(parentBeanFactory);
if (containsBean(parentHierarchicalBeanFactory, beanName)) {
return true;
}
}
return beanFactory.containsLocalBean(beanName);
}
private static void displayContainsLocalBean(HierarchicalBeanFactory beanFactory, String beanName) {
System.out.printf("当前 BeanFactory[%s] 是否包含 Local Bean[name : %s] : %s\n", beanFactory, beanName,
beanFactory.containsLocalBean(beanName));
}
private static ConfigurableListableBeanFactory createParentBeanFactory() {
// 创建 BeanFactory 容器
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
// XML 配置文件 ClassPath 路径
String location = "classpath:/META-INF/dependency-lookup-context.xml";
// 加载配置
reader.loadBeanDefinitions(location);
return beanFactory;
}
}
使用BeanFactoryUtils查找Bean
- 单一类型:BeanFactoryUtils#beanOfType
- 集合类型:BeanFactoryUtils#beansOfTypeIncludingAncestors
- 根据 Java 注解查找名称列表:BeanFactoryUtils#beanNamesForTypeIncludingAncestors
// org.springframework.beans.factory.BeanFactoryUtils#beansOfTypeIncludingAncestors(org.springframework.beans.factory.ListableBeanFactory, java.lang.Class<T>)
// 也是递归,从父容器查找到子容器
public static <T> Map<String, T> beansOfTypeIncludingAncestors(ListableBeanFactory lbf, Class<T> type)
throws BeansException {
Assert.notNull(lbf, "ListableBeanFactory must not be null");
Map<String, T> result = new LinkedHashMap<>(4);
result.putAll(lbf.getBeansOfType(type));
if (lbf instanceof HierarchicalBeanFactory) {
HierarchicalBeanFactory hbf = (HierarchicalBeanFactory) lbf;
if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) {
Map<String, T> parentResult = beansOfTypeIncludingAncestors(
(ListableBeanFactory) hbf.getParentBeanFactory(), type);
parentResult.forEach((beanName, beanInstance) -> {
if (!result.containsKey(beanName) && !hbf.containsLocalBean(beanName)) { // 有相同的bean优先使用父容器的
result.put(beanName, beanInstance);
}
});
}
}
return result;
}
4、延迟依赖查找(接口 - ObjectFactory)
延迟查找并非是Bean的延迟加载,跟@Lazy是两码事,延迟指的就是查找的时候并没有查找到想要查找的那个bean而是查找到了,objectFactory或者objectProvider。并且Provider还比Factory多了能查找出多个的功能。ObjectProvider#getxxx 方法 底层还是通过BeanFactory来进行依赖查找的,但是在进行依赖查找前,可以制定以下规则,比如Bean找到后,再设置额外的属性,完成一些用户的自定义需求;Bean没有找到,该如何处理。
理解什么是延迟依赖查找
延迟查找,我个人认为主要是给架构开发者使用的。非常典型的一个使用场景,就是SpringBoot里的自动配置,可以看看LettuceConnectionConfiguration这个类,这个类用于创建RedisClient。显然,RedisClient的创建是要根据用户的需求来创建的。
有些属性是必须的,可以在配置文件里配置,比如ip,port这种。Lettuce在创建RedisClient的时候,会从配置文件里读取这些数据来创建RedisClient。
但有些属性是非必须的,而且不能在配置文件里配置,比如开启读写分离,RedisClient在Lettuce内部,是通过一个Builder来创建的,如果要开启读写分离,这需要你在这个Builder在执行build的过程中,额外加一行:clientConfigurationBuilder.readFrom(ReadFrom.REPLICA);
问题就在这里,怎么让业务开发人员把这行代码加入到其内部的build流程中?这个问题,一种比较常见的思路,是使用模板方法,写一个抽象方法,调用它。具体的实现交给开发人员。
所以Lettuce设计了一个LettuceClientConfigurationBuilderCustomizer的类,他有一个customize方法,并且把上面提到的Builder作为这个方法的参数传递进来。开发人员,如果能去配置LettuceClientConfigurationBuilderCustomizer这样一个类,就能达到上述的目的。
但问题是,如果是开发人员去配置这样一个类,说明LettuceClientConfigurationBuilderCustomizer这个类还没有被实例化。但根据模板模式,流程中必须调用LettuceClientConfigurationBuilderCustomizer这个类的抽象方法,才能达到目的。
这个时候延迟加载,ObjectProvider的作用就体现出来了。他可以规定,他产生的是一个LettuceClientConfigurationBuilderCustomizer的对象,并且指定这个对象产生以后,做什么事情。比如调用customize方法。
如果用户配置了LettuceClientConfigurationBuilderCustomizer对象。那么在创建RedisClient的流程中,ObjectProvider就能拿到该对象,然后按照预先指定的动作执行,比如执行customize方法。
如果用户没配置,那么拿不到Bean对象,就什么都不做。
所以这个场景,我认为是延迟查找的一个典型实现
// 根本在于函数式接口的使用 就是下面的第四行
private void customize(LettuceClientConfiguration.LettuceClientConfigurationBuilder builder) {
this.builderCustomizers.orderedStream()
.forEach((customizer) -> customizer.customize(builder));
}
熟悉ObjectFactory的子接口-ObjectProvider接口
public interface ObjectProvider<T> extends ObjectFactory<T>, Iterable<T> {
// 返回对象一个实例,args为创建相应实例时使用的参数
T getObject(Object... args) throws BeansException;
// 返回bean实例,如果不可用则为空
@Nullable
T getIfAvailable() throws BeansException;
// 返回bean实例,如果不可用则使用默认的Supplier
default T getIfAvailable(Supplier<T> defaultSupplier) throws BeansException {
T dependency = getIfAvailable();
return (dependency != null ? dependency : defaultSupplier.get());
}
// 如果可用,调用消费者
default void ifAvailable(Consumer<T> dependencyConsumer) throws BeansException {
T dependency = getIfAvailable();
if (dependency != null) {
dependencyConsumer.accept(dependency);
}
}
// 如果不可用或不唯一,则为空
@Nullable
T getIfUnique() throws BeansException;
// 如果不可用或不唯一,则使用Supplier
default T getIfUnique(Supplier<T> defaultSupplier) throws BeansException {
T dependency = getIfUnique();
return (dependency != null ? dependency : defaultSupplier.get());
}
// 如果可用唯一,调用消费者Consumer
default void ifUnique(Consumer<T> dependencyConsumer) throws BeansException {
T dependency = getIfUnique();
if (dependency != null) {
dependencyConsumer.accept(dependency);
}
}
// 可遍历,支持stream
@Override
default Iterator<T> iterator() {
return stream().iterator();
}
default Stream<T> stream() {
throw new UnsupportedOperationException("Multi element access not supported");
}
// 获取排序后的数据流
default Stream<T> orderedStream() {
throw new UnsupportedOperationException("Ordered element access not supported");
}
}
延迟加载ObjectProvider使用示例
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
/**
* 通过 {@link ObjectProvider} 进行依赖查找
*/
public class ObjectProviderDemo { // 这里@Configuration 是非必须注解
public static void main(String[] args) {
// 创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 将当前类 ObjectProviderDemo 作为配置类(Configuration Class)
applicationContext.register(ObjectProviderDemo.class);
// 启动应用上下文
applicationContext.refresh();
// 依赖查找集合对象
lookupByObjectProvider(applicationContext);
lookupIfAvailable(applicationContext);
lookupByStreamOps(applicationContext);
// 关闭应用上下文
applicationContext.close();
}
private static void lookupByStreamOps(AnnotationConfigApplicationContext applicationContext) {
ObjectProvider<String> objectProvider = applicationContext.getBeanProvider(String.class);
// Iterable<String> stringIterable = objectProvider;
// for (String string : stringIterable) {
// System.out.println(string);
// }
// Stream -> Method reference
objectProvider.stream().forEach(System.out::println);
}
private static void lookupIfAvailable(AnnotationConfigApplicationContext applicationContext) {
ObjectProvider<User> userObjectProvider = applicationContext.getBeanProvider(User.class);
User user = userObjectProvider.getIfAvailable(User::createUser); // 如果没有,就创建对象
System.out.println("当前 User 对象:" + user);
}
@Bean
@Primary
public String helloWorld() { // 方法名就是 Bean 名称 = "helloWorld"
return "Hello,World";
}
@Bean
public String message() {
return "Message";
}
private static void lookupByObjectProvider(AnnotationConfigApplicationContext applicationContext) {
ObjectProvider<String> objectProvider = applicationContext.getBeanProvider(String.class);
System.out.println(objectProvider.getObject());
}
}
5、依赖查找的异常安全性
依赖查找类型 | 代表实现— | 是否安全 |
---|---|---|
单一类型查找 | BeanFactory#getBean | 否 |
ObjectFactory#getObject | 否 | |
ObjectProvider#getIfAvailable | 是 | |
集合类型查找 | ListableBeanFactory#getBeansOfType | 是 |
ObjectProvider#stream | 是 |
注意:层次性依赖查找的安全性取决于其扩展的单一或集合类型的 BeanFactory 接口
安全依赖查找代码实例
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* 类型安全 依赖查找示例
*/
public class TypeSafetyDependencyLookupDemo {
public static void main(String[] args) {
// 创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 将当前类 TypeSafetyDependencyLookupDemo 作为配置类(Configuration Class)
applicationContext.register(TypeSafetyDependencyLookupDemo.class); // 这里面是没有User的
// 启动应用上下文
applicationContext.refresh();
// 演示 BeanFactory#getBean 方法的安全性
displayBeanFactoryGetBean(applicationContext);
// 演示 ObjectFactory#getObject 方法的安全性
displayObjectFactoryGetObject(applicationContext);
// 演示 ObjectProvider#getIfAvaiable 方法的安全性
displayObjectProviderIfAvailable(applicationContext);
// 演示 ListableBeanFactory#getBeansOfType 方法的安全性
displayListableBeanFactoryGetBeansOfType(applicationContext);
// 演示 ObjectProvider Stream 操作的安全性
displayObjectProviderStreamOps(applicationContext);
// 关闭应用上下文
applicationContext.close();
}
private static void displayObjectProviderStreamOps(AnnotationConfigApplicationContext applicationContext) {
ObjectProvider<User> userObjectProvider = applicationContext.getBeanProvider(User.class);
/**
* userObjectProvider.forEach是安全的
*/
printBeansException("displayObjectProviderStreamOps", () -> userObjectProvider.forEach(System.out::println));
}
private static void displayListableBeanFactoryGetBeansOfType(ListableBeanFactory beanFactory) {
/**
* beanFactory.getBeansOfType(User.class) 是安全的
* 找不到bean不会抛异常,会返回空(并不是null)
*/
printBeansException("displayListableBeanFactoryGetBeansOfType", () -> beanFactory.getBeansOfType(User.class));
}
private static void displayObjectProviderIfAvailable(AnnotationConfigApplicationContext applicationContext) {
ObjectProvider<User> userObjectProvider = applicationContext.getBeanProvider(User.class);
/**
* objectProvider.getIfAvailable() 是安全的
* 找不到bean会返回null
*/
printBeansException("displayObjectProviderIfAvailable", () -> userObjectProvider.getIfAvailable());
}
private static void displayObjectFactoryGetObject(AnnotationConfigApplicationContext applicationContext) {
// ObjectProvider 等价于 ObjectFactory
ObjectFactory<User> userObjectFactory = applicationContext.getBeanProvider(User.class);
/**
* ObjectFactory.getObject()不安全!
* 没有该Bean会抛异常
*/
printBeansException("displayObjectFactoryGetObject", () -> userObjectFactory.getObject());
}
public static void displayBeanFactoryGetBean(BeanFactory beanFactory) {
/**
* beanFactory.getBean(User.class) 不安全!
* beanFactory.getBean(class); 有三种情况会抛异常
* NoSuchBeanDefinitionException -如果没有找到给定类型的bean
* NoUniqueBeanDefinitionException——如果找到了多个给定类型的bean
* BeansException -如果无法创建bean
*/
printBeansException("displayBeanFactoryGetBean", () -> beanFactory.getBean(User.class));
}
private static void printBeansException(String source, Runnable runnable) {
System.err.println("==========================================");
System.err.println("Source from :" + source);
try {
runnable.run();
} catch (BeansException exception) {
exception.printStackTrace();
}
}
}
由依赖查找的异常安全性做出的总结
日常开发中能用异常安全的方式获取Bean就用安全的方式获取Bean,这里推荐使用ObjectProvider的方式获取Bean,既可以单一类型查找,又可以集合类型查找,使用方便还安全。
6、Spring内建可查找的依赖
AbstractApplicationContext 内建可查找的依赖
Bean 名称 | Bean 实例 | 使用场景 |
---|---|---|
environment | Environment 对象 | 外部化配置(-D启动参数)以及 Profiles |
systemProperties | java.util.Properties 对象 | Java 系统属性 |
systemEnvironment | java.util.Map 对象 | 操作系统环境变量(当前用户) |
messageSource | MessageSource 对象 | 国际化文案 |
lifecycleProcessor | LifecycleProcessor 对象 | Lifecycle Bean 处理器 |
applicationEventMulticaster | ApplicationEventMulticaster 对象 | Spring 事件广播器 |
注解驱动 Spring 应用上下文内建可查找的依赖
Bean 名称 | Bean 实例 | 使用场景 |
---|---|---|
org.springframework.context.annotation.internalConfigurationAnnotationProcessor | ConfigurationClassPostProcessor 对象 | 处理 Spring 配置类 |
org.springframework.context.annotation.internalAutowiredAnnotationProcessor | AutowiredAnnotationBeanPostProcessor 对象 | 处理 @Autowired 以及 @Value注解 |
org.springframework.context.annotation.internalCommonAnnotationProcessor | CommonAnnotationBeanPostProcessor 对象 | (条件激活)处理 JSR-250 注解,如 @PostConstruct 等 |
org.springframework.context.event.internalEventListenerProcessor | EventListenerMethodProcessor对象 | 处理标注 @EventListener 的Spring 事件监听方法 |
org.springframework.context.event.internalEventListenerFactory | DefaultEventListenerFactory 对象 | @EventListener 事件监听方法适配为 ApplicationListener |
org.springframework.context.annotation.internalPersistenceAnnotationProcessor | PersistenceAnnotationBeanPostProcessor 对象 | (条件激活)处理 JPA 注解场景 |
1、ConfigurationClassPostProcessor
标注了@Configuration 的类,底层是由ConfigurationClass处理的。
而ConfigurationClassPostProcessor 实现了BeanDefinitionRegistryPostProcessor,用于处理BeanFactory的生命周期回调。
2、AutowiredAnnotationBeanPostProcessor
从其构造器也可以看出,它是处理@Autowired和@Value的。
public AutowiredAnnotationBeanPostProcessor() {
this.autowiredAnnotationTypes.add(Autowired.class);
this.autowiredAnnotationTypes.add(Value.class);
try {
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.
}
}
7、依赖查找中的经典异常
BeansException 子类型
异常类型 | 触发条件(举例) | 场景举例 |
---|---|---|
NoSuchBeanDefinitionException | 当查找 Bean 不存在于 IoC 容器时 | BeanFactory#getBean、 ObjectFactory#getObject |
NoUniqueBeanDefinitionException | 类型依赖查找时,IoC 容器存在多个 Bean 实例 | BeanFactory#getBean(Class) |
BeanInstantiationException | 当 Bean 所对应的类型非具体类时 | BeanFactory#getBean |
BeanCreationException | 当 Bean 初始化过程中 | Bean 初始化方法执行异常时 |
BeanDefinitionStoreException | 当 BeanDefinition 配置元信息非法时 | XML 配置资源无法打开时 |
附1:各个BeanFactory的继承关系
附2:ApplicationContext继承关系
二、依赖注入
依赖注入类型:
依赖注入类型 | 配置元数据举例 |
---|---|
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 { … } |
1、自动绑定(Autowiring-区别于@Autowired)
其实自动绑定的方式更多的是使用xml的方式,实际自动绑定有很多限制和不足,日常开发过程中较少使用。
模式 | 说明 |
---|---|
no | 默认值,未激活 Autowiring,需要手动指定依赖注入对象 |
byName | 根据被注入属性的名称作为 Bean 名称进行依赖查找,并将对象设置到该属性 |
byType | 根据被注入属性的类型作为依赖类型进行查找,并将对象设置到该属性 |
constructor | 特殊 byType 类型,用于构造器参数 |
<!--使用ref的方式,可以将addressBean命名的bean绑定到address字段-->
<!--使用parent的方式,指定父类-->
<bean id="superUser" class="com.demo.domain.SuperUser" parent="user">
<property name="address" ref="addressBean"/>
</bean>
<!--autowire自动绑定有多种模式,上面已经介绍过 -->
<bean id="user" class="com.demo.domain.SuperUser" autowire="byName">
</bean>
每种自动绑定的模式都或多或少有一些坑:
- no:需要自己手动指定注入对象,value或者ref。
- byName:属性名与被注入的bean名必须相同,如果有修改需要同步修改。
- byType:如果有多个类型的bean,需要指定@Primary。不能绑定如String类型这种原生类型。
Autowire是一个枚举,指定的自动绑定的模式:
// 我们可以看到,枚举类型并没有构造器绑定,其实构造器绑定就是一种byType绑定
// 具体详情可以查看AutowireCapableBeanFactory
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);
public boolean isAutowire() {
return (this == BY_NAME || this == BY_TYPE);
}
}
2、Setter 方法注入
自动Setter注入
自动Setter注入有byName和byType的方式,具体参考上面介绍的自动绑定。
手动Setter注入
1、XML资源配置元信息
<!-- 使用name+value的方式,可以实现手动Setter注入 -->
<bean class="com.demo.User">
<property name="name" value="张三" />
</bean>
2、Java 注解配置元信息
// User在容器中已经注册过了,只需要作为方法参数传过来,就会自动获取到
@Bean
public UserHolder userHolder(User user) {
UserHolder userHolder = new UserHolder();
userHolder.setUser(user);
return userHolder;
}
3、API 配置元信息
// 生成 UserHolder 的 BeanDefinition
BeanDefinition userHolderBeanDefinition = createUserHolderBeanDefinition();
// 注册 UserHolder 的 BeanDefinition
applicationContext.registerBeanDefinition("userHolder", userHolderBeanDefinition);
// 生成UserHolder 的 BeanDefinition
private static BeanDefinition createUserHolderBeanDefinition() {
BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserHolder.class);
definitionBuilder.addPropertyReference("user", "superUser"); // 设置属性关联,将superUser命名的bean,赋值到user属性
return definitionBuilder.getBeanDefinition();
}
3、构造器注入(官方推荐)
自动构造器注入
详情请看文章上面,自动绑定。
<bean class="org.geekbang.thinking.in.spring.ioc.dependency.injection.UserHolder"
autowire="constructor">
<!-- <property name="user" ref="superUser" /> 替换成 autowiring 模式 -->
</bean>
手动构造器注入
1、xml方式
<!--自定义构造器参数,ref代表bean的名称 -->
<bean class="org.geekbang.thinking.in.spring.ioc.dependency.injection.UserHolder">
<constructor-arg name="user" ref="superUser" />
</bean>
public class UserHolder {
private User user;
public UserHolder(User user) {
this.user = user;
}
2、注解方式
@Bean
public UserHolder userHolder(User user) {
return new UserHolder(user);
}
3、API方式
private static BeanDefinition createUserHolderBeanDefinition() {
BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserHolder.class);
definitionBuilder.addConstructorArgReference("superUser"); // 自动找到名称为superUser的bean,注入到构造器
return definitionBuilder.getBeanDefinition();
}
4、字段注入
字段注入一般使用Java 注解配置元信息:
- @Autowired
- @Resource
- @Inject(可选)
/**
使用@Autowired 注入,默认根据类型注入,然后根据name注入
注意!@Autowired会忽略static类型的字段,具体源码后续再讲
*/
@Autowired
private UserHolder userHolder;
/**
使用@Resource 注入,默认根据类型注入,然后根据name注入
*/
@Resource
private UserHolder userHolder2;
/**
使用@Inject 注入,需要依赖JSR-330的jar包,这里略
*/
5、方法注入
方法注入一般使用Java 注解配置元信息:
- @Autowired
- @Resource
- @Inject(可选)
- @Bean
方法注入会自动匹配bean为方法的参数,将其注入到方法的参数中。
方法注入不走 factorybean, Setter 注入是通过 Java Beans 来实现的,而方法注入则是直接通过 Java 反射来做的。当然底层都是 Java 反射~
private UserHolder userHolder;
private UserHolder userHolder2;
@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);
}
6、接口回调注入
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 对象,用于占位符处理 |
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.Aware;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* 基于 {@link Aware} 接口回调的依赖注入示例
*/
public class AwareInterfaceDependencyInjectionDemo implements BeanFactoryAware, ApplicationContextAware {
private static BeanFactory beanFactory;
private static ApplicationContext applicationContext;
public static void main(String[] args) {
// 创建 BeanFactory 容器
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
// 注册 Configuration Class(配置类) -> Spring Bean
context.register(AwareInterfaceDependencyInjectionDemo.class);
// 启动 Spring 应用上下文
context.refresh();
System.out.println(beanFactory == context.getBeanFactory());
System.out.println(applicationContext == context);
// 显示地关闭 Spring 应用上下文
context.close();
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
AwareInterfaceDependencyInjectionDemo.beanFactory = beanFactory;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
AwareInterfaceDependencyInjectionDemo.applicationContext = applicationContext;
}
}
7、各种依赖注入比较
注入方式 | 优点 | 缺点 |
---|---|---|
构造器注入 | 通用性强,官方推荐 | 无法解决循环依赖问题;参数过多的话可读性差 |
Setter 方法注入 | 解决循环依赖问题 | 不能将对象设置为final |
字段注入 | 使用便捷 | 不能将字段设为final、static;无法解决循环依赖问题 |
方法注入 | 一般与@Bean配合使用,@Autowire、@Resource用的较少 |
8、基础类型的注入
- 原生类型(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 等
使用xml配置的方式,一些基础类型的配置涉及自动类型转换:
public class User {
private Long id;
private String name;
private City city; // 枚举
private Resource configFileLocation; // 资源
public enum City {
BEIJING,
HANGZHOU,
SHANGHAI
}
<bean id="user" class="com.demo.domain.User">
<property name="id" value="1"/>
<property name="name" value="张三"/>
<property name="city" value="HANGZHOU"/>
<property name="configFileLocation" value="classpath:/META-INF/user-config.properties"/>
</bean>
9、集合类型注入
- 数组类型(Array):原生类型、标量类型、常规类型、Spring 类型
- 集合类型(Collection)
- Collection:List、Set(SortedSet、NavigableSet、EnumSet)
- Map:Properties
public class User {
private City[] workCities; // 数组
private List<City> lifeCities; // list
public enum City {
BEIJING,
HANGZHOU,
SHANGHAI
}
<bean id="user" class="com.demo.domain.User">
<property name="workCities" value="BEIJING,HANGZHOU"/> <!-- list也可以用这种方式写 -->
<property name="lifeCities">
<list>
<value>BEIJING</value>
<value>SHANGHAI</value>
</list>
</property>
</bean>
10、限定注入
使用注解 @Qualifier 通过Bean 名称限定
有多个同类型的Bean时,使用@Primary指定默认的Bean之后,再使用@Autowired会自动注入使用@Primary指定的Bean,否则会报错。
使用@Qualifier(“user”),可以注入指定名称的bean。
@Autowired
private User user;
@Autowired
@Qualifier("user") // 指定 Bean 名称或 ID
private User namedUser;
@Bean
public User user() {
return createUser(5L);
}
@Bean
@Primary // 指定默认
public User users() {
return createUser(6L);
}
使用注解 @Qualifier 通过分组限定
当使用@Bean定义一个bean时,同时使用@Qualifier标注,此bean就会被分组。
使用@Autowired注入时,同时使用@Qualifier标注,会取出分组过的bean。
@Autowired // 注入所有User类型的Bean
private Collection<User> allUsers;
@Autowired
@Qualifier // 取出所有使用@Qualifier标注的bean
private Collection<User> qualifiedUsers;
@Bean
@Qualifier // 进行逻辑分组
public User user1() {
return createUser(7L);
}
@Bean
@Qualifier // 进行逻辑分组
public User user2() {
return createUser(8L);
}
基于注解 @Qualifier 扩展限定
(自定义注解 - 实际应用如 Spring Cloud @LoadBalanced)
我们可以使用@Qualifier扩展分组,扩展后的用法与@Qualifier相同。
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Qualifier
public @interface UserGroup {
}
@Autowired
@UserGroup
private Collection<User> groupedUsers;
@Bean
@UserGroup
public User user3() {
return createUser(9L);
}
@Bean
@UserGroup
public User user4() {
return createUser(10L);
}
案例
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Qualifier
public @interface UserGroup {
}
import org.geekbang.thinking.in.spring.ioc.dependency.injection.annotation.UserGroup;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import java.util.Collection;
@Configuration
public class QualifierAnnotationDependencyInjectionDemo {
@Autowired // 注入使用 @Primary标注的bean
private User user;
@Autowired
@Qualifier("user") // 指定 Bean 名称或 ID
private User namedUser;
@Autowired // 注入所有User类型的bean
private Collection<User> allUsers;
@Autowired
@Qualifier // 注入使用@Qualifier 分组的bean
private Collection<User> qualifiedUsers;
@Autowired
@UserGroup // 注入使用@UserGroup、@Qualifier分组的bean(因为@UserGroup用@Qualifier标注了)
private Collection<User> groupedUsers;
@Bean
public User user() {
return createUser(5L);
}
@Bean
@Primary // 指定默认
public User users() {
return createUser(6L);
}
@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;
}
public static void main(String[] args) {
// 创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 注册 Configuration Class(配置类) -> Spring Bean
applicationContext.register(QualifierAnnotationDependencyInjectionDemo.class);
// 启动 Spring 应用上下文
applicationContext.refresh();
// 依赖查找 QualifierAnnotationDependencyInjectionDemo Bean
QualifierAnnotationDependencyInjectionDemo demo = applicationContext.getBean(QualifierAnnotationDependencyInjectionDemo.class);
// 期待输出 superUser Bean
System.out.println("demo.user = " + demo.user);
// 期待输出 user Bean
System.out.println("demo.namedUser = " + demo.namedUser);
// 期待输出 superUser user user1 user2
System.out.println("demo.allUsers = " + demo.allUsers);
// 期待输出 user1 user2
System.out.println("demo.qualifiedUsers = " + demo.qualifiedUsers);
// 期待输出 user3 user4
System.out.println("demo.groupedUsers = " + demo.groupedUsers);
// 显示地关闭 Spring 应用上下文
applicationContext.close();
}
}
// 输出内容
demo.user = User{id=6}
demo.namedUser = User{id=5}
demo.allUsers = [User{id=5}, User{id=6}, User{id=7}, User{id=8}, User{id=9}, User{id=10}]
demo.qualifiedUsers = [User{id=7}, User{id=8}, User{id=9}, User{id=10}]
demo.groupedUsers = [User{id=9}, User{id=10}]
11、延迟依赖注入
延迟依赖注入请参考【延迟依赖查找】。
通常的 @Autowired 会及时依赖相关的 Spring Bean,不过此时 Bean 的状态并未完全准备好,所以 ObjectProvider 可以在需要时获取 Spring Bean,更好的状态准备,达到延迟的获取效果。(更多请查阅【Spring如何解决循环依赖的】)
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Collection;
import java.util.Set;
/**
* {@link ObjectProvider} 实现延迟依赖注入
*/
@Configuration
public class LazyAnnotationDependencyInjectionDemo {
@Autowired
@Qualifier("user")
private User user; // 实时注入
@Autowired
private ObjectProvider<User> userObjectProvider; // 使用 API ObjectFactory 延迟注入
@Autowired
private ObjectFactory<Set<User>> usersObjectFactory; // 使用 API ObjectProvider 延迟注入(推荐)
@Bean
public User user() {
return createUser(10L);
}
private static User createUser(Long id) {
User user = new User();
user.setId(id);
return user;
}
public static void main(String[] args) {
// 创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 注册 Configuration Class(配置类) -> Spring Bean
applicationContext.register(LazyAnnotationDependencyInjectionDemo.class);
// 启动 Spring 应用上下文
applicationContext.refresh();
// 依赖查找 QualifierAnnotationDependencyInjectionDemo Bean
LazyAnnotationDependencyInjectionDemo demo = applicationContext.getBean(LazyAnnotationDependencyInjectionDemo.class);
// 期待输出 superUser Bean
System.out.println("demo.user = " + demo.user);
// 期待输出 superUser Bean
System.out.println("demo.userObjectProvider = " + demo.userObjectProvider.getObject()); // 继承 ObjectFactory
// 期待输出 superUser user Beans
System.out.println("demo.usersObjectFactory = " + demo.usersObjectFactory.getObject());
demo.userObjectProvider.forEach(System.out::println);
// 显示地关闭 Spring 应用上下文
applicationContext.close();
}
}
12、Optional类型注入
java8开始支持Optional类型,直接定义Optional的泛型,就会根据定义的泛型进行注入。
@Autowired
private Optional<User> userOptional;
13、依赖注入处理的过程源码分析
入口 - DefaultListableBeanFactory#resolveDependency
// org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency
@Override
@Nullable
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
if (Optional.class == descriptor.getDependencyType()) { // java8开始支持Optional
return createOptionalDependency(descriptor, requestingBeanName);
}
else if (ObjectFactory.class == descriptor.getDependencyType() ||
ObjectProvider.class == descriptor.getDependencyType()) { // 支持ObjectProvider
return new DependencyObjectProvider(descriptor, requestingBeanName);
}
else if (javaxInjectProviderClass == descriptor.getDependencyType()) { // Java 中jsr330注入方式
return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
}
else { // 默认操作
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary( // 是否懒加载
descriptor, requestingBeanName);
if (result == null) {
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
}
// org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency
@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
Object shortcut = descriptor.resolveShortcut(this);
if (shortcut != null) {
return shortcut;
}
Class<?> type = descriptor.getDependencyType();
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
if (value instanceof String) {
String strVal = resolveEmbeddedValue((String) value);
BeanDefinition bd = (beanName != null && containsBean(beanName) ?
getMergedBeanDefinition(beanName) : null);
value = evaluateBeanDefinitionString(strVal, bd);
}
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
try {
return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
}
catch (UnsupportedOperationException ex) {
// A custom TypeConverter which does not support TypeDescriptor resolution...
return (descriptor.getField() != null ?
converter.convertIfNecessary(value, type, descriptor.getField()) :
converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
}
}
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
// 会返回多个bean
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
String autowiredBeanName;
Object instanceCandidate;
if (matchingBeans.size() > 1) { // 多个bean
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
}
else {
// In case of an optional Collection/Map, silently ignore a non-unique case:
// possibly it was meant to be an empty collection of multiple regular beans
// (before 4.3 in particular when we didn't even look for collection beans).
return null;
}
}
instanceCandidate = matchingBeans.get(autowiredBeanName);
}
else {
// We have exactly one match.
Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
autowiredBeanName = entry.getKey();
instanceCandidate = entry.getValue();
}
if (autowiredBeanNames != null) {
autowiredBeanNames.add(autowiredBeanName);
}
if (instanceCandidate instanceof Class) {
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
Object result = instanceCandidate;
if (result instanceof NullBean) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
result = null;
}
if (!ClassUtils.isAssignableValue(type, result)) {
throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
}
return result;
}
finally {
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
}
// org.springframework.beans.factory.support.DefaultListableBeanFactory#findAutowireCandidates
protected Map<String, Object> findAutowireCandidates(
@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this, requiredType, true, descriptor.isEager());
Map<String, Object> result = CollectionUtils.newLinkedHashMap(candidateNames.length);
for (Map.Entry<Class<?>, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {
Class<?> autowiringType = classObjectEntry.getKey();
if (autowiringType.isAssignableFrom(requiredType)) {
Object autowiringValue = classObjectEntry.getValue();
autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
if (requiredType.isInstance(autowiringValue)) {
result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
break;
}
}
}
for (String candidate : candidateNames) {
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
if (result.isEmpty()) {
boolean multiple = indicatesMultipleBeans(requiredType);
// Consider fallback matches if the first pass failed to find anything...
DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
for (String candidate : candidateNames) {
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor) &&
(!multiple || getAutowireCandidateResolver().hasQualifier(descriptor))) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
if (result.isEmpty() && !multiple) {
// Consider self references as a final pass...
// but in the case of a dependency collection, not the very same bean itself.
for (String candidate : candidateNames) {
if (isSelfReference(beanName, candidate) &&
(!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&
isAutowireCandidate(candidate, fallbackDescriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
}
}
return result;
}
// 获取bean集合
// org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveMultipleBeans
@Nullable
private Object resolveMultipleBeans(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) {
Class<?> type = descriptor.getDependencyType();
if (descriptor instanceof StreamDependencyDescriptor) {
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (autowiredBeanNames != null) {
autowiredBeanNames.addAll(matchingBeans.keySet());
}
Stream<Object> stream = matchingBeans.keySet().stream()
.map(name -> descriptor.resolveCandidate(name, type, this))
.filter(bean -> !(bean instanceof NullBean));
if (((StreamDependencyDescriptor) descriptor).isOrdered()) {
stream = stream.sorted(adaptOrderComparator(matchingBeans));
}
return stream;
}
else if (type.isArray()) {
Class<?> componentType = type.getComponentType();
ResolvableType resolvableType = descriptor.getResolvableType();
Class<?> resolvedArrayType = resolvableType.resolve(type);
if (resolvedArrayType != type) {
componentType = resolvableType.getComponentType().resolve();
}
if (componentType == null) {
return null;
}
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType,
new MultiElementDescriptor(descriptor));
if (matchingBeans.isEmpty()) {
return null;
}
if (autowiredBeanNames != null) {
autowiredBeanNames.addAll(matchingBeans.keySet());
}
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
Object result = converter.convertIfNecessary(matchingBeans.values(), resolvedArrayType);
if (result instanceof Object[]) {
Comparator<Object> comparator = adaptDependencyComparator(matchingBeans);
if (comparator != null) {
Arrays.sort((Object[]) result, comparator);
}
}
return result;
}
else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
Class<?> elementType = descriptor.getResolvableType().asCollection().resolveGeneric();
if (elementType == null) {
return null;
}
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType,
new MultiElementDescriptor(descriptor));
if (matchingBeans.isEmpty()) {
return null;
}
if (autowiredBeanNames != null) {
autowiredBeanNames.addAll(matchingBeans.keySet());
}
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
Object result = converter.convertIfNecessary(matchingBeans.values(), type);
if (result instanceof List) {
if (((List<?>) result).size() > 1) {
Comparator<Object> comparator = adaptDependencyComparator(matchingBeans);
if (comparator != null) {
((List<?>) result).sort(comparator);
}
}
}
return result;
}
else if (Map.class == type) {
ResolvableType mapType = descriptor.getResolvableType().asMap();
Class<?> keyType = mapType.resolveGeneric(0);
if (String.class != keyType) {
return null;
}
Class<?> valueType = mapType.resolveGeneric(1);
if (valueType == null) {
return null;
}
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType,
new MultiElementDescriptor(descriptor));
if (matchingBeans.isEmpty()) {
return null;
}
if (autowiredBeanNames != null) {
autowiredBeanNames.addAll(matchingBeans.keySet());
}
return matchingBeans;
}
else {
return null;
}
}
14、详解@Autowired 注入
重要类:AutowiredAnnotationBeanPostProcessor。
@Autowired注入过程(所有方法都在AutowiredAnnotationBeanPostProcessor#类里)
(1)调用postProcessProperties()方法(spring 5.1之后才是这个方法名,5.1之前是postProcessPropertyValues)
该步骤信息点:
a. postProcessProperties方法会比bean的setXX()方法先调用
b.findAutowiringMetadata()方法会找出一个bean加了@Autowired注解的字段(包括父类的),并且该方法做了缓存
c.xml配置的bean与bean之间是可以有继承关系的,有另一个周期(不是autowired的流程)是把配置super bean的属性合并到当前bean,之后会调用后置方法postProcessMergedBeanDefinition,该方法也会调用一次findAutowiringMetadata
d.经测试,postProcessMergedBeanDefinition会比postProcessProperties先执行,因此调用postProcessProperties时都是直接拿缓存
(2)—>inject方法(获得对应的bean,然后通过反射注入到类的字段上)
(3)inject方法会调用resolveDependency方法,这方法会根据@Autowired字段信息来匹配出符合条件的bean
// org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
if (this.cached) {
try {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
catch (NoSuchBeanDefinitionException ex) {
// Unexpected removal of target bean for cached argument -> re-resolve
value = resolveFieldValue(field, bean, beanName);
}
}
else {
value = resolveFieldValue(field, bean, beanName);
}
if (value != null) { // 通过反射注入字段中
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
// org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#resolveFieldValue
@Nullable
private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
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();
Object value;
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) {
Object cachedFieldValue = null;
if (value != null || this.required) {
cachedFieldValue = desc;
registerDependentBeans(beanName, autowiredBeanNames);
if (autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
cachedFieldValue = new ShortcutDependencyDescriptor(
desc, autowiredBeanName, field.getType());
}
}
}
this.cachedFieldValue = cachedFieldValue;
this.cached = true;
}
}
return value;
}
15、JSR-330 @Inject 注入
要用@Inject,首先要引入jar包:
<!-- JSR-330 API -->
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
通过添加JSR-330的依赖来让AutowiredAnnotationBeanPostProcessor支持@Inject的annotationType。
// org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#AutowiredAnnotationBeanPostProcessor
// 可以处理@Autowired、@Value、以及判断是否有@Inject 选择是否支持
public AutowiredAnnotationBeanPostProcessor() {
this.autowiredAnnotationTypes.add(Autowired.class);
this.autowiredAnnotationTypes.add(Value.class);
try {
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.
}
}
// org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#findAutowiredAnnotation
// 一个字段同时标注三个注解时,注解处理有序,@Autowired > @Value > @Inject
@Nullable
private MergedAnnotation<?> findAutowiredAnnotation(AccessibleObject ao) {
MergedAnnotations annotations = MergedAnnotations.from(ao);
for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
MergedAnnotation<?> annotation = annotations.get(type);
if (annotation.isPresent()) {
return annotation;
}
}
return null;
}
@Inject 的使用和@Autowired 并没有区别:
@Inject
private User injectedUser;
16、Java通用注解注入原理
主处理类:CommonAnnotationBeanPostProcessor(与AutowiredAnnotationBeanPostProcessor非常类似)
注入注解:
- javax.xml.ws.WebServiceRef
- javax.ejb.EJB
- javax.annotation.Resource
生命周期注解:
- javax.annotation.PostConstruct
- javax.annotation.PreDestroy
// 支持以上注解:WebServiceRef、EJB、Resource、PostConstruct、PreDestroy
static {
resourceAnnotationTypes.add(Resource.class);
webServiceRefClass = loadAnnotationType("javax.xml.ws.WebServiceRef");
if (webServiceRefClass != null) {
resourceAnnotationTypes.add(webServiceRefClass);
}
ejbClass = loadAnnotationType("javax.ejb.EJB");
if (ejbClass != null) {
resourceAnnotationTypes.add(ejbClass);
}
}
public CommonAnnotationBeanPostProcessor() {
setOrder(Ordered.LOWEST_PRECEDENCE - 3);// 注意!优先级顺序
setInitAnnotationType(PostConstruct.class);
setDestroyAnnotationType(PreDestroy.class);
ignoreResourceType("javax.xml.ws.WebServiceContext");
// java.naming module present on JDK 9+?
if (jndiPresent) {
this.jndiFactory = new SimpleJndiBeanFactory();
}
}
// 生命周期回调:org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor#buildLifecycleMetadata
private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
if (!AnnotationUtils.isCandidateClass(clazz, Arrays.asList(this.initAnnotationType, this.destroyAnnotationType))) {
return this.emptyLifecycleMetadata;
}
List<LifecycleElement> initMethods = new ArrayList<>(); // 只允许绑定方法,LifecycleElement中有invoke方法
List<LifecycleElement> destroyMethods = new ArrayList<>(); // 只允许绑定方法,LifecycleElement中有invoke方法
Class<?> targetClass = clazz;
do {
final List<LifecycleElement> currInitMethods = new ArrayList<>();
final List<LifecycleElement> currDestroyMethods = new ArrayList<>();
// 构建原信息
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
LifecycleElement element = new LifecycleElement(method);
currInitMethods.add(element);
if (logger.isTraceEnabled()) {
logger.trace("Found init method on class [" + clazz.getName() + "]: " + method);
}
}
if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
currDestroyMethods.add(new LifecycleElement(method));
if (logger.isTraceEnabled()) {
logger.trace("Found destroy method on class [" + clazz.getName() + "]: " + method);
}
}
});
initMethods.addAll(0, currInitMethods);
destroyMethods.addAll(currDestroyMethods);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
return (initMethods.isEmpty() && destroyMethods.isEmpty() ? this.emptyLifecycleMetadata :
new LifecycleMetadata(clazz, initMethods, destroyMethods));
}
// org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.LifecycleElement
private static class LifecycleElement {
private final Method method;
private final String identifier;
public LifecycleElement(Method method) {
if (method.getParameterCount() != 0) {
throw new IllegalStateException("Lifecycle method annotation requires a no-arg method: " + method);
}
this.method = method;
this.identifier = (Modifier.isPrivate(method.getModifiers()) ?
ClassUtils.getQualifiedMethodName(method) : method.getName());
}
public Method getMethod() {
return this.method;
}
public String getIdentifier() {
return this.identifier;
}
// 方法回调执行
public void invoke(Object target) throws Throwable {
ReflectionUtils.makeAccessible(this.method);
this.method.invoke(target, (Object[]) null);
}
@Override
public boolean equals(@Nullable Object other) {
if (this == other) {
return true;
}
if (!(other instanceof LifecycleElement)) {
return false;
}
LifecycleElement otherElement = (LifecycleElement) other;
return (this.identifier.equals(otherElement.identifier));
}
@Override
public int hashCode() {
return this.identifier.hashCode();
}
}
17、自定义依赖注入注解
基于@Autowired元注解创建自定义注解
// 可以自行扩展
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Autowired
public @interface MyAutowired {
/**
* Declares whether the annotated dependency is required.
* <p>Defaults to {@code true}.
*/
boolean required() default true;
}
// 与@Autowired用法一致,可以自行扩展
@MyAutowired
private Optional<User> userOptional;
基于 AutowiredAnnotationBeanPostProcessor 实现
1、使用方式一:
/**
* 自定义依赖注入注解
*/
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.FIELD}) // 指定标注的位置
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface InjectedUser {
}
// Bean非常想要提前初始化 或者提前注册的话,可以将方法定义为static的
@Bean(name = AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)
public static AutowiredAnnotationBeanPostProcessor beanPostProcessor() {
AutowiredAnnotationBeanPostProcessor beanPostProcessor = new AutowiredAnnotationBeanPostProcessor();
// @Autowired + @Inject + 新注解 @InjectedUser
Set<Class<? extends Annotation>> autowiredAnnotationTypes =
new LinkedHashSet<>(Arrays.asList(Autowired.class, Inject.class, InjectedUser.class));
beanPostProcessor.setAutowiredAnnotationTypes(autowiredAnnotationTypes);
return beanPostProcessor;
}
// 使用新注解
@InjectedUser
private User myInjectedUser;
这种方式是完全将之前的AutowiredAnnotationBeanPostProcessor 替换了,但是@Inject有可能并没有引包,所以这里有一些小缺陷。
2、使用方式二:
先注册系统的AutowiredAnnotationBeanPostProcessor,再注册自定义的AutowiredAnnotationBeanPostProcessor,可以让两个同时存在。
@Bean
// 正常的@Autowired注解优先级为Ordered.LOWEST_PRECEDENCE - 2,这里比系统的AutowiredAnnotationBeanPostProcessor优先级低,会同时存在
@Order(Ordered.LOWEST_PRECEDENCE - 3)
public static AutowiredAnnotationBeanPostProcessor beanPostProcessor() {
AutowiredAnnotationBeanPostProcessor beanPostProcessor = new AutowiredAnnotationBeanPostProcessor();
beanPostProcessor.setAutowiredAnnotationType(InjectedUser.class);
return beanPostProcessor;
}
3、原理
在org.springframework.context.annotation.AnnotationConfigUtils 定义了一个bean:
public static final String AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME =
"org.springframework.context.annotation.internalAutowiredAnnotationProcessor";
// Bean不存在才自动注入,如果存在会优先使用用户自定义的
if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
自定义实现(略)
生命周期处理
- InstantiationAwareBeanPostProcessor
- MergedBeanDefinitionPostProcessor
元数据
- InjectedElement
- InjectionMetadata
19、附:关于加static的bean会提前注册问题
因为当 @Bean 方法定义是非 static 的话,那么它的初始化依赖于所属类 Bean 的初始化,而处理Demo属性的注入@Autowired属于Demo这个Bean初始化的一个环节,所以当 @Autowired 字段发生时,BeanPostProcessor后置处理器并没有创建好,所以@Autowired注解会失效。
采用static,将创建BeanPostProcessor后置处理器提前到了初始化Demo这个Bean之前,所以能够处理@Autowired注解。