侧边栏壁纸
博主头像
AE86小行星博主等级

行动起来,活在当下

  • 累计撰写 8 篇文章
  • 累计创建 6 个标签
  • 累计收到 1 条评论

目 录CONTENT

文章目录

Spring - Dependency Injection

Administrator
2021-09-20 / 0 评论 / 0 点赞 / 580 阅读 / 93732 字

所谓依赖注入,是指程序运行过程中,如果需要调用另一个对象协助时,无须在代码中创建被调用者,而是依赖于外部的注入。

Inject Mode And Type

依赖注入的模式和类型
依赖注入有自动注入(Autowring)手动注入两种模式,
Setter方法构造器字段方法接口回调五种类型
但是官方并不推荐自动模式

依赖注入的模式

自动模式 - 实现方提供依赖自动绑定方式,按照内建的注入规则

  • Autowiring

手动模式 - 配置或者编程的方式,提前安排注入规则

  • XML配置信息
  • Java注解配置信息
  • API配置信息

手动中的API配置信息方式日常开发很少使用,但是面向容器开发或者基于Spring进行扩展时,必须要会使用。

依赖注入的类型

依赖注入类型 配置信息举例 备注
Setter方法 ref时可以通过Bean的Id或名字或Alis(别名)引用到,
构造器 通过构造器参数注入属性,官方较为推荐
字段 @Autowirted BeanUser beanUser 官方不推荐,通过反射来修改类字段很危险,但是开发中使用这种方式很快捷
方法 @Autowirted public void BeanUserMethord(BeanUser beanUser){} 本质上和set方法注入一样,都是通过一个函数方法为字段赋值
接口回调 clsss BeanUser implements BeanFactoryAware 属于Spring的特殊方式,通过实现Aware接口,拿到一个BeanFactory,就可以自定义注入操作

Feature - Autowiring

Autowiring自动绑定是Spring的一个重要特性,Spring容器能够通过自动绑定的关系,在合作(组合、依赖于被依赖类)的Bean之间,以自动化的方式将Bean的合作者关联上。

优点 :可以有效的减少构造器或属性的设定/配置,会根据设置的byNamebyType自动寻找匹配的bean。
缺点:当设置自动绑定类型为byName时, 如果字段名称变了而Bean命没有变,会无法绑定上。
小节:显示的引用绑定大于隐式的绑定。

自动绑定的模式

使用方式

  • 注解:@Autowire
  • XML:auto-wire=''
模式 说明
no 默认值,未激活Autowiring,需要手动指定依赖注入对象
byName 根据被注入属性的名称做为Bean名称进行依赖查找,并将对象设置到该属性
byType 根据被注入属性的类型做为依赖类型进行查找,并将对象设置到该属性
constructor 特殊byType类型,用于构造器参数

所有模式,详见Autowire类

Autowiring自动绑定的不足

Autowiring主要匹配的是XML方式用,可以简化配置操作,但因为本身存在的歧义性,导致在实际中却很少用到。

  • 精确依赖问题
    • 构造器参数、方法参数上的值,可以覆盖掉Autowiring的值。
    • 自动绑定是一种猜测行为,精准性无法把控。
    • 多个Bean符合预期时,可能无法找到合适的方式去匹配(例如:byName无法定位且byType找到了多个的情况)。
  • 简单类型问题:
    • 因为自动绑定的是Bean这种对象,所以不可以绑定原生类型、String类型,Class类型(虽然不不可以自动绑定,但是可以使用@Value这种依赖注入的方式)
  • 工具本身问题:
    • Autowiring没有一个文档化的过程,只能通过静态的方式,去全部扫描是否缺失了Bean,无法提前预知。

为了避免这些歧义性出现在工程中

  • 可以关闭自动绑定模式
  • 可以设置autowire-candidate属性为false,以提醒显示的指定依赖。
  • 可以设置Beanprimary
  • 可as以增加注解配置进行详细配置

注入方式

Set方法注入

实现方式

  • 手动模式
    • XML配置
    • 注解配置
    • Spring API配置
  • 自动模式(Autowiring模式)
    • byName
    • byType

示例环境

//将User类注入到UserManage中
public class UserManage {
    private User user;
    public UserManage (){}
    public UserManage (User user){this.user = user;}
}

public class User {
    private Long id;
}

手动模式

xml配置示例

<beans>
    <bean class="Usermanage">
        <property name="user" ref="user" />
    </bean>
</beans>

注解配置示例

public class Demo {

    public static void main(String[] args) {
        // 创建 BeanFactory 容器,并将当前类 注册为 Configuration.class(配置类)
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(Demo.class);
        applicationContext.refresh();
        UserHolder userHolder = applicationContext.getBean(UserHolder.class);
        applicationContext.close();
    }

    //====================核心代码====================
    /**
    * 将User注入容器中
    * 因为容器的三级缓存原因,可以放在userManage下面,不会影响Bean的正常注册
    * @param user 拿到容器中的user,通过调用set方法注入字段
    */
    @Bean
    public UserManage userManage(User user) {
        UserManage userManage = new UserManage();
        userManage.setUser(user);
        return userHolder;
    }

    /**
    * 将User注入容器中
    * 因为容器的三级缓存原因,可以放在userManage下面,不会影响Bean的正常注册
    */
    @Bean
    public User user() {
        User user = new User();
        return user;
    }
    //====================核心代码====================

}

Spring API配置示例

public class Demo {

    public static void main(String[] args) {
        // 创建 BeanFactory 容器,并将当前类 注册为 Configuration.class(配置类)
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(Demo.class);

        //====================核心代码====================
        // 生成 UserManage 的 BeanDefinition
        BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserHolder.class);
        //假设已经通过注解或xml等方式,此时将User类注入进容器中
        definitionBuilder.addPropertyReference("user", "user");
        BeanDefinition userManageBeanDefinition = definitionBuilder.getBeanDefinition();
        // 注册 UserHolder 的 BeanDefinition
        applicationContext.registerBeanDefinition("userManage", userManageBeanDefinition);
        //====================核心代码====================

        applicationContext.refresh();
        // 依赖查找并且创建 Bean
        UserHolder userHolder = applicationContext.getBean(UserHolder.class);
        applicationContext.close();
    }
    
    /**
    * 先将User注入容器中
    */
    @Bean
    public User user() {
        User user = new User();
        return user;
    }
}

自动模式

自动绑定模式更多的是用在XML方式中,故显示XML的方式,注解方式中使用@Resource,其实就已经指定了Type与优先寻找的id

ByName方式xml配置示例

<beans>
    <bean class="Usermanage" autowire="byName">
<!--    会替代这部分代码,寻找容器中id名为user的Bean,再调用Set方法注入  -->
<!--    <property name="user" ref="user" />  -->
    </bean>
</beans>

ByType方式xml配置示例

<beans>
    <bean class="Usermanage" autowire="byType">
<!--    会替代这部分代码,寻找容器中Class类型为User的Bean,调用Set方法进行注入  -->
<!--    当出现多个匹配的Bean时,会使用设置为primary的Bean  -->
<!--    当出现多个标识primary的Bean,或者有多个没有设置primary的Bean的情况,就抛出异常,注入失败 -->
<!--    <property name="user" ref="user" />  -->
    </bean>
</beans>

如何即使用注解配置,又使用XML配置

public class Demo {
    public static void main(String[] args) {
        // 创建注解配置容器,设置XML读取类
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
        //定义XML文件地址,加载XML资源,解析并且生成 BeanDefinition
        String xmlResourcePath = "classpath:/META-INF/bean.xml";
        beanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
        //此时启动容器,就有了注解与XML中的Bean信息
        applicationContext.refresh();
    }
}

构造器注入

  • 手动模式
    • xml配置
    • Java注解配置
    • API配置
  • 自动模式
    • constructor

手动模式

xml配置示例

<beans>
    <bean class="Usermanage" autowire="byType">
        <construct-arg name="user" ref="user" />  
    </bean>
</beans>

注解配置示例

public class Demo {

    public static void main(String[] args) {
        // 创建 BeanFactory 容器,并将当前类 注册为 Configuration.class(配置类)
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(Demo.class);
        applicationContext.refresh();
        UserHolder userHolder = applicationContext.getBean(UserHolder.class);
        applicationContext.close();
    }

    //====================核心代码====================
    /**
    * @param user 容器中的user
    */
    @Bean
    public UserManage userManage(User user) {
        //调用UserManage的有参构造器,实现手动构造器注入
        UserManage userManage = new UserManage(user);
        return userHolder;
    }
    //====================核心代码====================

    /**
    * 将User注入容器中
    */
    @Bean
    public User user() {
        User user = new User();
        return user;
    }

}

Spring API配置示例

public class Demo {

    public static void main(String[] args) {
        // 创建 BeanFactory 容器,并将当前类 注册为 Configuration.class(配置类)
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(Demo.class);

        // 生成 UserManage 的 BeanDefinition
        BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserHolder.class);
        //====================核心代码====================
        //将容器中的User类,使用Api的方式进行构造器注入
        //此方法只有一个参数,就是Bean名
        //definitionBuilder.addConstructorArgReference(String)的调用顺序,就是UserManage的构造器参数顺序
        //这也是比Set方式注入更好的原因之一 ----- 可以指定顺序
        definitionBuilder.addConstructorArgReference("user");
        BeanDefinition userManageBeanDefinition = definitionBuilder.getBeanDefinition();
        //====================核心代码====================

        // 注册 UserHolder 的 BeanDefinition
        applicationContext.registerBeanDefinition("userManage", userManageBeanDefinition);
        applicationContext.refresh();
        // 依赖查找并且创建 Bean
        UserHolder userHolder = applicationContext.getBean(UserHolder.class);
        applicationContext.close();
    }
    
    /**
    * 先将User注入容器中
    */
    @Bean
    public User user() {
        User user = new User();
        return user;
    }
}

自动模式

constructor方式xml配置示例

<beans>
    <bean class="Usermanage" autowire="constructor">
<!--    <construct-arg name="user" ref="user" />   -->
<!--    会替代这部分代码,寻找容器中Class类型为User的Bean,调用构造器时进行注入  -->
<!--    当出现多个匹配的Bean时,会使用设置为primary的Bean  -->
<!--    当出现多个标识primary的Bean,或者有多个没有设置primary的Bean的情况,就抛出异常,注入失败 -->
    </bean>
</beans>

::: tip
这些基础性的知识,对于开发基于Spring的中间件,很重要
:::

字段方式注入

实现方式

  • 手动模式
    • 注解配置
      • @Autowired
      • @Resource
      • @inject(JSR-330引入的新注解)

手动模式代码示例

注解配置示例

public class Demo {

    //====================核心代码====================
    @Autowired
    //按照byType的方式查找Bean
    public User autoWiredUser;

    @Autowired
    //此处注入失败,@Autowire会忽略静态字段
    public static User statisUser;

    @Resource
    //@Resource不填写bean名时,按照byType的方式查找Bean
    public User resourceUser;

    @Inject
    //@Inject需单独引入JSR-330的jar包
    public User injectUser;

    //====================核心代码====================

    public static void main(String[] args) {
        // 创建 BeanFactory 容器,并将当前类 注册为 Configuration.class(配置类)
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(Demo.class);
        applicationContext.refresh();
        //此处debug,即可看到demo对象的各个user字段是否被注入
        Demo demo = applicationContext.getBean(Demo.class);
        applicationContext.close();
    }

    /**
    * 将User注入容器中
    */
    @Bean
    public User user() {
        User user = new User();
        return user;
    }

}

方法注入

实现方式

  • 手动模式
    • 注解配置
      • @Autowired
      • @Resource
      • @Inject
      • @Bean

手动模式

使用方法进行注入

public class Demo {

    //====================核心代码====================
    public User autoWiredUser;

    public User resourceUser;

    @Autowired
    //参数名就是Bean名,找不到就按照byType的方式查找Bean
    public void InitAutowiredUser(User autoWiredUser){
        this.autoWiredUser = autoWiredUser;
    }

    @Resource
    public void InitResourceUser(User resourceUser){
        this.resourceUser= resourceUser;
    }

    //====================核心代码====================

    public static void main(String[] args) {
        // 创建 BeanFactory 容器,并将当前类 注册为 Configuration.class(配置类)
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(Demo.class);
        applicationContext.refresh();
        //此处debug,即可看到demo对象的各个user字段是否被注入
        Demo demo = applicationContext.getBean(Demo.class);
        applicationContext.close();
    }

    /**
    * 将User注入容器中
    */
    @Bean
    public User user() {
        User user = new User();
        return user;
    }

}

感悟

加上了注解的方法,会在容器初始化时被执行,并且会带上Bean依赖信息,所以可以根据这种方式,对容器中的Bean进行各种操作

接口回调注入

实现方式

  • Aware接口回调
    • 自动模式
内建接口 说明 备注
BeanFactoryAware 获取IoC容器 - BeanFactory
ApplicationContextAware 获取Spring应用上下文 - ApplicationContext对象
EnvironmentAware 获取Environment对象
ResourceLoaderAware 获取资源加载器对象 - ResourceLoader
BeanClassLoaderAware 获取当前Bean Class的ClassLoader
BeanClassLoaderAware 获取加在当前Bean Class的ClassLoader
BeanNameAware 获取当前Bean的名称
MessageSourceAware 获取MessageSourceAware对象,用于国际化
ApplicationEventPublisherAware 获取ApplicationEventPublishAware对象,用于Spring事件
EmbeddedValueResolverAwar 获取StringValueResolver对象,用于占位符处理

都是内建的回调接口,暂时不能进行扩展

接口回调注入演示

BeanFactoryAwareApplicationContextAware演示

public class Demo implements BeanFactoryAware,ApplicationContextAware{

    //====================核心代码====================
    private static BeanFactory beanFactory;

    private static ApplicationContext context;

    @Override
    public void setBeanFactory(BeanFactory beanFactory){
        Demo.beanFactory = beanFactory;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext){
        Demo.context = applicationContext;
    }
    //====================核心代码====================

    public static void main(String[] args) {
        // 创建 BeanFactory 容器,并将当前类 注册为 Configuration.class(配置类)
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(Demo.class);
        applicationContext.refresh();
        //此处打印BeanFactory和ApplicationContext,查看是否被回调注入
        System.out.println(beanFactory == applicationContext.getBeanFactory);
        System.out.println(context == applictionContext);

        applicationContext.close();
    }

注入选型

  • 低依赖:构造器注入
  • 多依赖:Setter方法注入
  • 便利性:字段注入
  • 声明类:方法注入

基础类型注入

  • 原生类型(Primitive):八大类型
  • 标量类型(Scalar):Number(包括子类,如Integer等包装类)、Character,Boolean、Enum、Locale、Charset、Currency、Properties、UUID
  • 常规类型(General):Object、String、TimeZone、Calender、Optional等
  • Spring类型:Resource、InputSource、Formatter等

详细会在类型转换小节研究

集合类型注入

  • 数组类型(Array)
    • 原生类型、标量类型、常规类型、Spring类型
  • 集合类型(Collection)
    • Collection:List、Set
    • Map:Properties

XML中集合类型注入

<beans>
    <bean class="UserManage">
        <property name="userList" value="user1,user2" /> 
    </bean>
</beans>

限定注入

  • 使用@Qualifer限定
    • 通过Bean名称限定
    • 通过分组限定
  • 基于@Qualifer扩展
    • 自定义注解 - 如:@LoadBalanced

通过Bean名称限定注入配置示例

public class Demo {

    //====================核心代码====================
    @Autowired
    @Qualifer("user1")
    public User user3;

    @Autowired
    @Qualifer("user2")
    public User user4;

    //====================核心代码====================

    public static void main(String[] args) {
        // 创建 BeanFactory 容器,并将当前类 注册为 Configuration.class(配置类)
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(Demo.class);
        applicationContext.refresh();
        //此处debug,即可看到demo对象的user3、user4字段被按照Bean名注入
        Demo demo = applicationContext.getBean(Demo.class);
        applicationContext.close();
    }

    /**
    * 将User注入容器中
    */
    @Bean
    public User user1() {
        User user = new User();
        return user;
    }
    /**
    * 将User注入容器中
    */
    @Bean
    public User user2() {
        User user = new User();
        return user;
    }
}

通过分组限定配置示例

public class Demo {

    //====================核心代码====================
    @Autowired
    //会查找所有User --- 两个user
    public List<User> allUserList;

    @Autowired
    @Qualifer
    //会按照Qualifer分组查找 -- 只有一个user2 被注入
    public List<User> qualiferUserList;

    //====================核心代码====================

    public static void main(String[] args) {
        // 创建 BeanFactory 容器,并将当前类 注册为 Configuration.class(配置类)
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(Demo.class);
        applicationContext.refresh();
        //此处debug,即可看到demo对象的allUserList、qualiferUserList字段含有几个Bean
        Demo demo = applicationContext.getBean(Demo.class);
        applicationContext.close();
    }

    /**
    * 将User注入容器中
    */
    @Bean
    public User user1() {
        User user = new User();
        return user;
    }
    /**
    * 将User注入容器中
    */
    @Bean
    @Qualifer
    public User user2() {
        User user = new User();
        return user;
    }
}

自定义注解进行分组注入示例

@Qualifer
public @interface LoadBalanced{
  //因为loadBalance继承了@Qualifer,所以使用@loadBalance也会注入Bean,、
  //并且Bean会带上loadBalance的分组信息,此时就可以按照分组来注入
}
@Qualifer
public @interface QualiferGroup{
  //同样的,可以自定义注解继承@Qualifer,实现自定义分组
}
public class Demo {
    //====================核心代码====================
    @Autowired
    //会查找所有User --- 所有的三个user
    public List<User> allUserList;

    @Autowired
    @Qualifer
    //会按照Qualifer分组查找 -- 会有一个user2+一个user3,继承Qualifer的分组,也会被添加进来
    public List<User> qualiferUserList;

    @Autowired
    @LoadBalance
    //会按照LoadBalance分组查找 -- 只有一个user3
    public List<User> loadBalanceUserList;

    @Bean//注入普通user
    public User user1() {
        User user = new User();
        return user;
    }

    @Bean//注入含Qualifer分组信息的user
    @Qualifer
    public User user2() {
        User user = new User();
        return user;
    }

    @Bean//注入含LoadBalance分组信息的user
    @LoadBalance
    public User user3() {
        User user = new User();
        return user;
    }

    //====================核心代码====================

    public static void main(String[] args) {
        // 创建 BeanFactory 容器,并将当前类 注册为 Configuration.class(配置类)
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(Demo.class);
        applicationContext.refresh();
        //此处debug,即可看到demo对象的allUserList、qualiferUserList、loadBalanceUserList字段含有几个Bean
        Demo demo = applicationContext.getBean(Demo.class);
        applicationContext.close();
    }
}

注解元素的继承,也叫注解元素的派生

延迟依赖注入

  • API ObjectFactory延迟注入
    • 单一类型
    • 集合类型
  • API ObjectProvider延迟注入
    • 单一类型
    • 集合类型

推荐使用ObjectProvider,Api更多,使用方法更灵活

ObjectProvider延迟注入示例

@Qualifer
public @interface LoadBalanced{
  //因为loadBalance继承了@Qualifer,所以使用@loadBalance也会注入Bean,、
  //并且Bean会带上loadBalance的分组信息,此时就可以按照分组来注入
}
@Qualifer
public @interface QualiferGroup{
  //同样的,可以自定义注解继承@Qualifer,实现自定义分组
}
public class Demo {
    //====================核心代码====================
    @Autowired
    public ObjectProvider<User> providerUser;

    //@Autowired  //ObjectFactory获取单个user
    //public ObjectFactory<User> factorySingleUser;
    //@Autowired  //ObjectFactory获取多个user
    //public ObjectProvider<List<User>> factoryListUser;

    @Bean
    public User user() {
        User user = new User();
        return user;
    }
    //====================核心代码====================

    public static void main(String[] args) {
        // 创建 BeanFactory 容器,并将当前类 注册为 Configuration.class(配置类)
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(Demo.class);
        applicationContext.refresh();

        Demo demo = applicationContext.getBean(Demo.class);
        User user = demo.providerUser.getObject();//可以获取一个标记为primary的User
        demo.providerUser.foreach(System.sout::println)//可以获取注入的集合类型

        applicationContext.close();
    }
}

依赖处理过程

  • 基础知识
    • 依赖处理入口 - DefaultListableBeanFactory#resolveDependency
    • 依赖描述符 - DependencyDescriptor
    • 自动绑定候选对象处理器 - AutowireCandidateResolver

DefaultListableBeanFactory#resolveDependency

    /**
    * 2.5版本开始使用的两个重载方法作为基本的入口
    * 2.5版本之前是用的处理入口?待考证
    */
    Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName)
    /**
    * @param descriptor         依赖描述符
    * @param requestingBeanName 申请依赖注入的Bean(申请者)在容器中的名称
    * @param autowiredBeanNames 用以处理注入的BeanName的Set集合
    * @param typeConverter      类型转换器
    */
    Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter)

DependencyDescriptor.class

/**
* 存储依赖的描述信息
* 
* 部分注入点的信息(注入的类型、方法参数、字段信息、注解信息)
* 4.3后,存储在{@link InjectionPoint}中
* 4.3之前,存储在{@link DependencyDescriptor} 中  
*/
public class DependencyDescriptor extends InjectionPoint implements Serializable {
    /**
    * 申请注入操作的类(申请者)的类名
    */
    private final Class<?> declaringClass;
    /**
    * 使用方法注入时的方法名称
    * @Nullable 不使用方法注入时,允许为空
    */
    @Nullable
    private String methodName;
    /**
    * 使用方法/构造器注入时,方法/构造器参数的类型
    * @Nullable 不使用方法/构造器注入时,允许为空
    */
    @Nullable
    private Class<?>[] parameterTypes;
    /**
    * 参数的索引位
    */
    private int parameterIndex;
    /**
    * 使用字段注入时,被注入的字段名称
    * @Nullable 不使用方法注入时,允许为空
    * 以下三者必有其一不为空,否则没有注入的来源,会报错
    * {@link DependencyDescriptor#methodName}
    * {@link DependencyDescriptor#parameterTypes}
    * {@link DependencyDescriptor#fieldName}
    */
    @Nullable
    private String fieldName;
    /**
    * 是否是必须的,默认为true
    */
    private final boolean required;
    /**
    * 是否是饥饿的
    * 为true时,必须存在需要注入的bean,否则就报错
    * 为false时,相当于{@see Lazy}实现延迟加载、延迟注入
    */
    private final boolean eager;
    /**
    * 嵌入层级
    * ------
    * 在NestedDependencyDescriptor中,会将嵌套层级+1,代表
    * 目前我已知的
    * 使用NestedDependencyDescriptor的地方有:
    * - ObjectFactory.class
    * - ObjectProvider.class
    * - Optional<?>
    * 使用MultiElementDescriptor extend NestedDependencyDescriptor 的地方有
    * - array
    * - Map.class
    * - Collection.class.isAssignableFrom(type) && type.isInterface()
    * 由此可见,此层级代表的是,需要注入Bean在数据结构中的层级
    * 比如:@Autowrite private User;                                   ==> nestingLevel = 1(顶层,无嵌套)
    * 比如:@Autowrite List<User> userList;                            ==> nestingLevel = 2(依赖描述符发现是Collection的子接口,使用MultiElementDescriptor,层级加一)
    * 比如:@Autowrite ObjectFactory<User> userObjectFactory;           ==> nestingLevel = 2(依赖描述符使用NestedDependencyDescriptor,层级加一)
    * 比如:@Autowrite ObjectFactory<List<User>> userListObjectFactory; ==> nestingLevel = 3(ObjectFactory的依赖描述符使用NestedDependencyDescriptor,发现内部是List,又使用MultiElementDescriptor作为依赖描述符,经历了两次嵌套层级加一,最终为3)
    */
    private int nestingLevel = 1;
    /**
    * 申请处理依赖注入时的类名,通常和{@link DependencyDescriptor#declaringClass}是一个值,什么时候不一样?有待学习探查
    */
    @Nullable
    private Class<?> containingClass;
    /**
    * 泛型类型
    */
    @Nullable
    private transient volatile ResolvableType resolvableType;
    /**
    * 类型的描述符
    * @see DependencyDescriptor 描述依赖的信息
    * @see TypeDescriptor       描述泛型类型的信息
    */
    @Nullable
    private transient volatile TypeDescriptor typeDescriptor;
}

DependencyDescriptor 演示

public class Demo {
    //====================核心代码====================
    /**
    * 此处生成的依赖描述符:DependencyDescriptor ->
    * 申请注入的类:declaringClass = Demo.class 
    * 不是方法/构造器注入:methodName = null
    * 不是方法/构造器注入:parameterTypes = null
    * 参数索引位为默认0:parameterIndex = 0
    * 字段名称:fieldName = userDesc
    * 必须注入:required = true
    * 实时注入:eager = true
    * 嵌套层级为1:nestingLevel = 1
    * 包含类:containingClass = Demo.class 
    * 没有泛型:resolvableType = null
    * 泛型描述为null:typeDescriptor = null
    * 不是方法/构造器注入:methodParameter = null
    * 注入类的类型:field = User.class
    * 没有设置注解:fieldAnnotations = null
    * 使用位置{@link org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency(DependencyDescriptor , @Nullable String , @Nullable Set<String> , @Nullable TypeConverter )}
    */
    @Autowired
    public User userDesc;

    /**
    * 将User注入容器中
    */
    @Bean
    public User user() {
        User user = new User();
        return user;
    }
    //====================核心代码====================

    public static void main(String[] args) {
        // 创建 BeanFactory 容器,并将当前类 注册为 Configuration.class(配置类)
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(Demo.class);
        applicationContext.refresh();
        applicationContext.close();
    }
}

处理依赖的核心入口resolveDependency

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
		implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
    /**
    * 对Bean处理依赖的主要入口
    * 
    * @param descriptor         依赖描述符
    * @param requestingBeanName 请求注入bean的bean名称
    * @param autowiredBeanNames 自动注入时指定的bean名称
    * @param typeConverter      类型转换器
    */
    @Override
    @Nullable
    public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
    @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
        //在使用方法注入时,初始化参数探测器
        descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
        //如果是Optional,则创建特殊的Optional包装
        if (Optional.class == descriptor.getDependencyType()) {
            return createOptionalDependency(descriptor, requestingBeanName);
        }
        //如果是ObjectFactory/ObjectProvider这类延迟依赖,则创建延迟依赖处理器
        //DependencyObjectProvider --> BeanObjectProvider --> ObjectProvider --> ObjectFactory,所以返回DependencyObjectProvider不会报错
        else if (ObjectFactory.class == descriptor.getDependencyType() || ObjectProvider.class == descriptor.getDependencyType()) {
                return new DependencyObjectProvider(descriptor, requestingBeanName);
        }
        //Jsr330规范
        else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
            return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
        }
        //默认处理方法
        else {
            //默认返回null
            //暂时不是很懂这一行的具体用处 - 从BeanFactory获取自动绑定候选对象处理器的延迟代理
            Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary( descriptor, requestingBeanName);
            if (result == null) {
                //处理依赖的核心方法,业务程序大多数情况下使用的处理依赖的方法
                //包括上方DependencyObjectProvider内延迟依赖获取数据时,也是使用的此方法获取真实依赖数据
                result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
            }
            return result;
        }
    }

    /**
    * 处理依赖的核心方法
    * 根据依赖描述符、申请注入的Bean名称等信息,执行一系列操作,返回依赖对应的Bean实例
    */
    @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(); // <?>

            //从自动绑定候选对象处理器中获取推荐的值:
            //处理携带@Value时如何从配置文件中选取值的情况
            //此情况时,if内的分析后续完善...
            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()));
                }
            }
            //处理注入类型为集合的情况,例如:@Autowrite private List<User> userList;
            //存疑1待研究:内部有一个判断(Collection.class && isInterface) ==> 集合并且是接口,为什么要限制必须为接口?ArrayList就不当做集合处理了?
            //存疑1部分理解:应用程序可能会真的需要一个ArrayList类型的Bean,此时如果按照元素类型而不是ArrayList类型来进行依赖查找并注入,肯定是一个不符合期望的结果。而interface和class,一个负责定义规则,一个负责具体实例化。Spring将interface作为注入多个Bean的规则,将class作为用户具体创建的Bean,也很符合逻辑,Spring真是将面向对象完全理解透了!
            //存疑2待研究:Collection设计为Collection及其子类接口(Collection.class.isAssignableFrom(type))才按照元素类型注入,而Map为什么必须完全相等(Map.class == type)?
            //存疑2部分理解:可能因为Map的结构特殊?或者更多的使用场景?实在没有头绪
            //如果类型为集合,就会返回集合类型的Object
            //使用descriptor.getDependencyType()判断类型
            //方法内部候选类型:StreamDependencyDescriptor(Java 8 引入的) || isArray() || (Collection.class && isInterface) || Map.class ,都不匹配则返回null
            Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
            if (multipleBeans != null) {
                return multipleBeans;
            }
            //重点:使用申请注入Bean的bean名称、申请注入Bean的类型,依赖描述符,查找可以注入的候选者名单
            //key为候选者的Bean名,value可能是Bean的Class信息,也可能是实例化的Bean
            //注意!此方法需要后续再次复习,暂时没有理解内部方法的逻辑
            Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
            //如果没有候选者,就判断下是否是必须注入的
            //如果必须注入,就调用方法'raiseNoMatchingBeanFound()'抛出警告
            //如果不是必须注入,就返回null,此时Bean的字段为null,外部直接使用会报空指针
            if (matchingBeans.isEmpty()) {
                if (isRequired(descriptor)) {
                    raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
                }
                return null;
            }

            String autowiredBeanName;
            Object instanceCandidate;
            //当有多个候选者时
            if (matchingBeans.size() > 1) {
                //从候选者中决定(determine)被注入者的bean名称
                //内部会先判断是否有标记为primary的Bean(有多个primary则报错)
                //再根据Bean的优先级获取,如果Bean没有继承OrderComparator或没有实现@Order注解,则返回null表示没有找到合适的Bean
                //有多个优先级相同的Bean,则报错
                autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
                if (autowiredBeanName == null) {
                    //如果声明了必须注入,或者不是多个Bean类型(array、Collection、Map),则抛出NoUniqueBeanDefinitionException
                    //因为声明不必须,可以返回null。声明为多Bean(array、Map、<? extend Collection> && isInterface)类型,则不会走这段代码,会在上方的'resolveMultipleBeans'处理   <?>
                    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
                        // 它可能是多个普通Bean的空集合
                        // (before 4.3 in particular when we didn't even look for collection beans).
                        //(尤其是在4.3之前,我们甚至没有寻找收集bean集合)。
                        return null;
                    }
                }
                //从匹配的BeanMap中拿到需要注入的Bean
                instanceCandidate = matchingBeans.get(autowiredBeanName);
            }
            else {
                // We have exactly one match.
                // 程序走到这,说明匹配的Bean只有一个,所以直接'.iterator().next();'拿到数据
                Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
                autowiredBeanName = entry.getKey();
                instanceCandidate = entry.getValue();
            }
            //autowiredBeanNames 的用处暂时不是很懂,有待后续研究
            if (autowiredBeanNames != null) {
                autowiredBeanNames.add(autowiredBeanName);
            }
            //如果拿到的候选者value是一个Class,没有实例化,那就使用依赖描述符的获取候选者方法(执行getBean获取)返回Bean实例
            if (instanceCandidate instanceof Class) {
                instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
            }
            //校验下是否是NullBean
            Object result = instanceCandidate;
            if (result instanceof NullBean) {
                if (isRequired(descriptor)) {
                    raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
                }
                result = null;
            }
            //校验下拿到的类型和期望的类型是否匹配,不匹配就抛出BeanNotOfRequiredTypeException
            if (!ClassUtils.isAssignableValue(type, result)) {
                throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
            }
            //返回最终的实例Bean
            return result;
        }
        finally {
            ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
        }
    }
}

处理过程解释一

在 AbstractApplicationContext#refresh#finishBeanFactoryInitialization 方法中,初始化所有还未初始化的 Bean(不是抽象、单例模式、不是懒加载方式)

通过 DefaultListableBeanFactory#preInstantiateSingletons 方法进行初始化,会通过 AbstractBeanFactory#getBean(beanName) 方法对每个 Bean 进行初始化

Bean 初始化的过程比较繁琐,大致过程如下:

  1. 先找到对应的 BeanDefinition 对象,然后会走到 AbstractAutowireCapableBeanFactory#createBean 方法,进行实例化填充属性值、调用 Bean 的初始化方法

  2. 在填充属性值的过程,默认根据类型进行注入,那么在 AbstractAutowireCapableBeanFactory#autowireByType 的方法中会调用 DefaultListableBeanFactory#resolveDependency 方法进行注入,最后还是会通过 AbstractBeanFactory#getBean(beanName) 方法获取到需要注入的 Bean 对象

  3. 在填充属性值的时候也会通过 AutowiredAnnotationBeanPostProcessor 注入属性值,该注入增强器会对 @Autowired 或者 @Value 注解标注的属性进行注入,也是通过 DefaultListableBeanFactory#resolveDependency 方法进行注入。具体过程可看 AutowiredAnnotationBeanPostProcessor 的私有内部类 AutowiredFieldElement#inject 方法


处理过程解释二

DefaultListableBeanFactory#resolveDependency -->
1.判断是否懒加载–>doResolveDependency()
2.判断是否是多类型的bean resolveMultipleBeans()
3.根据类型查找匹配到的bean findAutowireCandidates()
4.bean个数大于1,选择bean即@Primary修饰 determineAutowireCandidate()
5.返回结果


零碎知识点

  • 注入类型为Map<K,V>时,Spring默认实现是LinkedHashMap,含有顺序

@Autowired注入的规则与原理

注入过程

  • 源信息解析
  • 依赖查找
  • 依赖注入(字段、方法)

::: tip 关键名词
RootBeanDefinition:合并后,不可以再合并的根bean定义信息
PropertyValues:从XML或者Annotation中获得的属性信息(字符、instance、数值等)
AbstractAutowireCapableBeanFactory:注入处理的地方
InstantiationAwareBeanPostProcessor#postProcessProperties:初始化结束后的回调接口,可以在此接口中修改Bean的属性
AbstractAutowireCapableBeanFactory#createBean:创建Bean的方法
AbstractAutowireCapableBeanFactory#populateBean:创建Bean得到实例后,为实例注入属性的方法(初始化阶段),也是此知识点最主要的方法
:::

源信息解析

  • 需要知道Bean需要注入哪些东西->合并BeanDefinition拿到->遍历查找指定Class的字段、方法,并递归查找父类,查看需要注入些什么东西
  • 如果携带(@Autowrite/@Resource/@Value/Class<? extends Annotation>),则将Field/Method临时封装在InjectionMetadata中,作为准备注入到Bean中的依赖元信息
  • 解析(类型转换)成对应属性信息PropertyValues,buildAutowiringMetadata
  • InjectionMetadata在填充Bean属性时使用
  • 解析成DependencyDescriptor

依赖查找

  • 依赖处理

依赖注入(字段、方法)

处理过程解释一

1.在doCreateBean中会先调用applyMergedBeanDefinitionPostProcessors,后执行populateBean
所以会先调用postProcessMergedBeanDefinition后执行InstantiationAwareBeanPostProcessor的postProcessProperties。
2.postProcessProperties中有两个步骤:
(1)findAutowiringMetadata查找注入元数据,没有缓存就创建,具体是上一节内容。最终会返回InjectionMetadata,里面包括待注入的InjectedElement信息(field、method)等等
(2)执行InjectionMetadata的inject方法,具体为AutowiredFieldElement和AutowiredMethodElement的Inject方法
(2.1)AutowiredFieldElement inject具体流程:
(2.1.1)DependencyDescriptor的创建
(2.1.2)调用beanFactory的resolveDependency获取带注入的bean
(2.1.2.1)resolveDependency根据具体类型返回候选bean的集合或primary 的bean
(2.1.3)利用反射设置field


处理过程解释二

简单的说先合并BeanDefinition(因此存在继承关系所以需要合并父与子的BeanDefinition),合并好了之后就是要创建Bean,创建bean肯定要看看有没有配置什么字段需要注入->findAutowiringMetadata()。

但其实在合并BeanDefinition时候已经find过一次了,因为毕竟是BeanDefinition,元信息肯定是需要知道所有的,因此findAutowiringMetadata是有缓存的,所以postProcessProperties的findAutowiringMetadata其实查的是缓存。

那找到了需要的AutowiringMetadata之后肯定是要注入了,找到了结果叫InjectionMetadata,调用inject。inject步骤是先创建DependencyDescriptor,然后beanFactory.resolveDependency(DependencyDescriptor …),得到bean之后然后反射set字段


处理过程解释三

1.bean特殊实例化中讲过,通过AbstractAutowireCapableBeanFactory#createBean()–>doCreateBean()
2.AbstractAutowireCapableBeanFactory#doCreateBean()包括两部分
2.1 合并BeanDefinition处理操作,applyMergedBeanDefinitionPostProcessors()方法,最后调用AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition查找自动注入的元信息来封装注入元素信息即InjectionMetadata#checkedElements
2.2 填充bean的过程populateBean()方法1422行最后调用AutowiredAnnotationBeanPostProcessor#postProcessProperties方法分为两部分
2.2.1 查找自动注入元信息,findAutowiringMetadata()方法,缓存中存在则直接取不存在则构建
2.2.2 注入执行inject,具体为InjectionMetadata.InjectedElement的实现类AutowiredMethodElement的inject()方法,715通过依赖查找的方式来注入依赖即上一讲的DefaultListableBeanFactory的resolveDependency过程


处理过程解释四

先是找元信息然后进行注入:主要流程:AbstractAutowireCapableBeanFactory#createBean()–>doCreateBean()
1.调用applyMergedBeanDefinitionPostProcessors -> postProcessMergedBeanDefinition -> findAutowiringMetadata中找到该类中注解为Autowired、Value、Inject的字段、方法等
2.调用populateBean -> postProcessProperties,先调用findAutowiringMetadata找到待注入的元信息(比如user),然后调用metadata的inject方法,底层调用的是AutowiredFieldElement和AutowiredMethodElement的inject方法,
2.1 构造DependencyDescriptor(比如user)
2.2 调用beanFactory.resolveDependency获取待注入的bean(比如user),这里又是一轮的createBean(比如superUser不存在,则会创建)
2.3 获取后进行反射注入:field.set(bean, value)


注入部分的分析理应是在populationBean中,但是applyMergedBeanDefinitionPostProcessors中又有大量的设置Bean属性的知识点,虽然是Spring留给开发者的扩展点,但在Bean属性注入时,又有很重要的作用。
思来想去,还是决定从doCreateBean开始分析,梳理applyMergedBeanDefinitionPostProcessorspopulationBean的主要流程

创建Bean主要流程doCreateBean源码解析

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {
    /**
     * 实际创建指定的bean的方法
     * 此时已经完成了创建(实例化)前的处理
     * 可以进行Bean属性赋值前置操作、Bean创建、Bean属性赋值后置操作
     * 
     * @param beanName Bean的名称
     * @param mbd 因为Bean有继承(extend)关系(注解:extend Xxx,Xml:parent="xxx"),所以需要拿到合并<b>继承关系</b>后的BeanDefinition => {@Link RootBeanDefinition},这才有一个Bean需要注入的所有信息
     * @param args 方法注入或者构造器注入时的参数
     * @return 一个新的Bean实例
     */
    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException {

        // Instantiate the bean.
        // 实例化的Bean会先放在BeanWrapper中放着,最后再从BeanWrapper中取出来,类似代理?装饰者?
        BeanWrapper instanceWrapper = null;
        // 如果是单例,那就可以从缓存中拿
        if (mbd.isSingleton()) {
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        //缓存中没有数据,会使用反射拿到构造器创建Bean {@link Class#getDeclaredConstructor}
        if (instanceWrapper == null) {
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        final Object bean = instanceWrapper.getWrappedInstance();
        Class<?> beanType = instanceWrapper.getWrappedClass();
        if (beanType != NullBean.class) {
            mbd.resolvedTargetType = beanType;
        }

        // Allow post-processors to modify the merged bean definition.
        synchronized (mbd.postProcessingLock) {
            // postProcessed:仅包内可见,判断MergedBeanDefinitionPostProcessor(BeanDefinition信息合并)流程是否被应用/使用过
            if (!mbd.postProcessed) {
                try {
                    // 执行所有的MergedBeanDefinitionPostProcessor,包含Spring自带的和用户自己添加的
                    // 业务开发时,通常不会自己实现MergedBeanDefinitionPostProcessor来扩展Spring
                    applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                }
                catch (Throwable ex) {
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                            "Post-processing of merged bean definition failed", ex);
                }
                // 调用结束,设置合并流程已被调用过
                mbd.postProcessed = true;
            }
        }

        // Eagerly cache singletons to be able to resolve circular references
        // even when triggered by lifecycle interfaces like BeanFactoryAware.
        // 有点重要,会涉及到Spring如何处理循环依赖
        // 在创建Bean的初期,将Bean的早期引用放入缓存中
        // 如果后续出现循环依赖,可以先拿引用缓存,保证Bean不会因为缺少依赖而不能实例化
        // 这样,在初始化时就能拿到实例进行赋值
        //   如果Bean是单例 ==> 默认单例
        //   并且允许自动处理Bean之间的循环引用 ==> 默认允许
        //   并且Bean处于实例化阶段 ==> createBean
        //     ==> 创建早期Bean引用并添加到缓存中 ==> addSingletonFactory
        //   Bean的缓存地点:
        //     ==> DefaultSingletonBeanRegistry#singletonFactories
        //     ==> DefaultSingletonBeanRegistry#registeredSingletons
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
        if (earlySingletonExposure) {
            if (logger.isTraceEnabled()) {
                logger.trace("Eagerly caching bean '" + beanName +
                        "' to allow for resolving potential circular references");
            }
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }

        // Initialize the bean instance.
        Object exposedObject = bean;
        try {
            // 主要方法:填充Bean中的属性,详细解析在下方
            populateBean(beanName, mbd, instanceWrapper);
            // 执行Bean初始化时的各种回调方法,方法内支持修改Bean的属性
            // 暂不详细分析,到生命周期的文章中详细分析
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
        catch (Throwable ex) {
            if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
                throw (BeanCreationException) ex;
            }
            else {
                throw new BeanCreationException(
                        mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
            }
        }
        //以下方法暂不分析,先专注在注入属性上
        if (earlySingletonExposure) {
            Object earlySingletonReference = getSingleton(beanName, false);
            if (earlySingletonReference != null) {
                if (exposedObject == bean) {
                    exposedObject = earlySingletonReference;
                }
                else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                    String[] dependentBeans = getDependentBeans(beanName);
                    Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
                    for (String dependentBean : dependentBeans) {
                        if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                            actualDependentBeans.add(dependentBean);
                        }
                    }
                    if (!actualDependentBeans.isEmpty()) {
                        throw new BeanCurrentlyInCreationException(beanName,
                                "Bean with name '" + beanName + "' has been injected into other beans [" +
                                        StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
                                        "] in its raw version as part of a circular reference, but has eventually been " +
                                        "wrapped. This means that said other beans do not use the final version of the " +
                                        "bean. This is often the result of over-eager type matching - consider using " +
                                        "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
                    }
                }
            }
        }

        // Register bean as disposable.
        try {
            registerDisposableBeanIfNecessary(beanName, bean, mbd);
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
        }

        return exposedObject;
    }
}

属性初始化流程populateBean源码解析

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {

    /**
     * 为了将Bean中定义的属性,创建Bean实例并填充到当前申请注入的Bean中
     * 也就是付出实践了,从书面定义到实际添加
     * 
     * @param beanName Bean的名称
     * @param mbd Bean最终的定义信息 ==> RootBeanDefinition
     * @param bw Bean的包装者,放着真正使用的Bean实例
     */
    @SuppressWarnings("deprecation")  // for postProcessPropertyValues
    protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
        // 如果包装这Bean的包装者都为null,那还定义了有属性,null.setXxx?肯定得报错啊
        // 但是什么情况下bw为null?粗略的看了下源码中的调用情况,发现传入时都不会为null。此处待研究。
        if (bw == null) {
            if (mbd.hasPropertyValues()) {
                throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
            }
            else {
                // Skip property population phase for null instance.
                return;
            }
        }

        // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
        // state of the bean before properties are set. This can be used, for example,
        // to support styles of field injection.
        // 一个扩展点:如果Bean实现了InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation方法,就会在这里回调,做自己想做的事。
        // 打印日志?记录创建链路信息?修改Bean信息?都可以~
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    // 如果返回false,则结束整个初始化流程
                    if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                        return;
                    }
                }
            }
        }
        // 判断mdb中是否有注入信息,没有就返回null
        // 一个小细节点:因为调用getPropertyValues时,没有属性就会触发初始化属性值的设置
        //              所以避免错误初始化,使用hasPropertyValues判断
        PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

        // 这一段的整体目的是,根据注入方式(AUTOWIRE_BY_NAME,AUTOWIRE_BY_TYPE),拿到注入的属性数据,并添加到PropertyValues 中
        // 比如需要注入一个user,那这里就会PropertyValues中添加一个user-instance的映射关系
        //   ==> 当然,为了拿到user的instance,肯定也会触发doCreateBean和population,又递归到这里了
        // 注意:此时并没有将属性注入到Bean中,而是将属性放到了psv里
        //   ==> 既然这个方法有bw,可以直接将属性设置到Bean中,但为什么不设置进去呢?
        //     ==> 因为Spring想给开发者更多的扩展点,扩展点就是下方的使用boolean hasInstAwareBpps的逻辑
        //     ==> 使开发者尽可能的在Bean的不同阶段,有控制/处理Bean的能力
        //     ==> 这里的控制能力,就是:在Bean真正赋值之前的开发自定义功能的能力
        int resolvedAutowireMode = mbd.getResolvedAutowireMode();
        if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
            // 创建一个新的PropertyValues并集成旧PropertyValues中的值
            MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

            // Add property values based on autowire by name if applicable.
            // 根据Bena名称拿到Bean的名称信息
            if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
                autowireByName(beanName, mbd, bw, newPvs);
            }
            // Add property values based on autowire by type if applicable.
            // 根据Bena类型拿到Bean的名称信息
            if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
                autowireByType(beanName, mbd, bw, newPvs);
            }
            // 难道最初这一段逻辑封装在一个方法里?所以会有创建了又赋值回来的操作?
            pvs = newPvs;
        }

        // 判断Bean时候含有实例化时的前置/后置操作,默认是有的 ==> 注解驱动时是:AutowiredAnnotationBeanPostProcessor.class
        boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
        // 是否需要进行依赖检查,查阅文章时发现,原来在3.0的时候就弃用了,代替者是构造器注入或者@Required,默认值为:DEPENDENCY_CHECK_NONE,不强制进行检查
        boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

        PropertyDescriptor[] filteredPds = null;
        if (hasInstAwareBpps) {
            // 通过上方的注入类型的判断可以知道,通过名称和类型注入时,psv都不会为空,那就只用使用构造器注入时回会为null,此时调用getPropertyValues()方法,初始化一下psv为空集合
            if (pvs == null) {
                pvs = mbd.getPropertyValues();
            }
            // 重要流程:这里是Spring给开发者的扩展点,在Bean注入属性之前注入属性时的关键点
            // Spring正是使用这个扩展点,执行真正注入属性的方法。沿用自身的设计逻辑,而不使用硬编码去注入信息,面向对象玩得很溜了
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                // 判断流程操作是不是初始化回调流程
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    // 进行强转
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    // 重点方法,一个扩展点,此处可以设置PropertyValues的值,PropertyValues全部设置好了,才进行最后的属性填充
                    // Spring在这里,通过BeanFactory查找与反射的方式,对Bean进行了属性的赋值
                    // 注意:经过Spring的默认流程处理,此时bw.getWrappedInstance()中的属性已经被赋值,这里返回的pvsToUse 是为了给后面的applyPropertyValues使用
                    PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
                    // 如果返回null,说明属性没有改变,继续调用已弃用的方法处理psv
                    if (pvsToUse == null) {
                        if (filteredPds == null) {
                            filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
                        }
                        // 5.1时弃用的方法,无论有没有更新,都返回新psv,如果要中断填充bean的流程,就返回null
                        pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                        if (pvsToUse == null) {
                            return;
                        }
                    }
                    pvs = pvsToUse;
                }
            }
        }
        // 暂不分析,我也不是很懂
        if (needsDepCheck) {
            if (filteredPds == null) {
                filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
            }
            checkDependencies(beanName, mbd, filteredPds, pvs);
        }
        // 拿到了需要注入的属性,开始真正应用这些值
        if (pvs != null) {
            applyPropertyValues(beanName, mbd, bw, pvs);
        }
    }

    /**
     * 这是一个很重要的方法,但是涉及的东西太多了,暂时先不梳理,以后再回头来处理
     * Apply the given property values, resolving any runtime references
     * to other beans in this bean factory. Must use deep copy, so we
     * don't permanently modify this property.
     * @param beanName the bean name passed for better exception information
     * @param mbd the merged bean definition
     * @param bw the BeanWrapper wrapping the target object
     * @param pvs the new property values
     */
    protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
        if (pvs.isEmpty()) {
            return;
        }

        if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) {
            ((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
        }

        MutablePropertyValues mpvs = null;
        List<PropertyValue> original;

        if (pvs instanceof MutablePropertyValues) {
            mpvs = (MutablePropertyValues) pvs;
            if (mpvs.isConverted()) {
                // Shortcut: use the pre-converted values as-is.
                try {
                    bw.setPropertyValues(mpvs);
                    return;
                }
                catch (BeansException ex) {
                    throw new BeanCreationException(
                            mbd.getResourceDescription(), beanName, "Error setting property values", ex);
                }
            }
            original = mpvs.getPropertyValueList();
        }
        else {
            original = Arrays.asList(pvs.getPropertyValues());
        }

        TypeConverter converter = getCustomTypeConverter();
        if (converter == null) {
            converter = bw;
        }
        BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);

        // Create a deep copy, resolving any references for values.
        List<PropertyValue> deepCopy = new ArrayList<>(original.size());
        boolean resolveNecessary = false;
        for (PropertyValue pv : original) {
            if (pv.isConverted()) {
                deepCopy.add(pv);
            }
            else {
                String propertyName = pv.getName();
                Object originalValue = pv.getValue();
                if (originalValue == AutowiredPropertyMarker.INSTANCE) {
                    Method writeMethod = bw.getPropertyDescriptor(propertyName).getWriteMethod();
                    if (writeMethod == null) {
                        throw new IllegalArgumentException("Autowire marker for property without write method: " + pv);
                    }
                    originalValue = new DependencyDescriptor(new MethodParameter(writeMethod, 0), true);
                }
                Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
                Object convertedValue = resolvedValue;
                boolean convertible = bw.isWritableProperty(propertyName) &&
                        !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
                if (convertible) {
                    convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
                }
                // Possibly store converted value in merged bean definition,
                // in order to avoid re-conversion for every created bean instance.
                if (resolvedValue == originalValue) {
                    if (convertible) {
                        pv.setConvertedValue(convertedValue);
                    }
                    deepCopy.add(pv);
                }
                else if (convertible && originalValue instanceof TypedStringValue &&
                        !((TypedStringValue) originalValue).isDynamic() &&
                        !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
                    pv.setConvertedValue(convertedValue);
                    deepCopy.add(pv);
                }
                else {
                    resolveNecessary = true;
                    deepCopy.add(new PropertyValue(pv, convertedValue));
                }
            }
        }
        if (mpvs != null && !resolveNecessary) {
            mpvs.setConverted();
        }

        // Set our (possibly massaged) deep copy.
        try {
            bw.setPropertyValues(new MutablePropertyValues(deepCopy));
        }
        catch (BeansException ex) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Error setting property values", ex);
        }
    }
}

InstantiationAwareBeanPostProcessor#postProcessProperties接口解释

    /**
     *
     * 5.1时新增的回调方法,执行初始化回调方法,此时会提供以下信息给开发者,给开发者调整psv的能力
     * 如果需要调整PropertyValues ,就返回调整后的PropertyValues
     * 如果不需要调整PropertyValues,就返回null,将会调用旧版已弃用的方法
     * 
     * InstantiationAwareBeanPostProcessor有两个默认实现
     *   ==> 实现一:CommonAnnotationBeanPostProcessor
     *   ==> 在@WebServiceRef、@EJB、@Resourcet这三种注入方式时会有对应回调
     *  ==> 实现二:AutowiredAnnotationBeanPostProcessor
     *     ==> 在@Autowired、@Value、@Inject这三种注入方式时会有对应回调
     * 本次使用实现一:{@link AutowiredAnnotationBeanPostProcessor}来分析Bean在注入时的逻辑与规则,在下方进行详细解释
     * 
     * @param pvs                     --- 待注入属性信息,第一次进入时的值为属性名:详见上方autowireByName和autowireByType
     * @param bw.getWrappedInstance() --- 最终会返回的真实Bean
     * @param beanName                --- Bean的名称
     */
    @Nullable
    default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
            throws BeansException {

        return null;
    }

注解形式的自动注入,在填充PropertiesValues时的实现

注解形式的自动注入AutowiredAnnotationBeanPostProcessorInstantiationAwareBeanPostProcessor#postProcessProperties的实现
扩展知识点:Java方法桥接

public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {

    /**
     * 注解形式的自动注入,会使用反射的形式,遍历Bean的字段和方法,查找哪些地方需要填充Bean实例
     * 但是会将具体逻辑委托给InjectionMetadata.InjectedElement去实现
     * 因为支持字段和方法的@Autowrite,所以InjectionMetadata.InjectedElement有两个实现
     * 实现一:{@link AutowiredFieldElement}  字段级别的注入信息
     * 实现二:{@link AutowiredMethodElement} 方法级别的注入信息
     * 两个实现的逻辑差别不大,此处使用{@link AutowiredFieldElement}进行详细分析
     * 构造器级别的注入,在另一个生命周期注入,暂不在此方法处理
     * 
     * @param pvs      暂存属性值的对象
     * @param bean     待填充属性的Bean对象
     * @param beanName Bean的名称
     */
    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
        // 因为注解写在类上,所以方法内部使用Bean的class信息寻找Bean所需的参数,
        InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
        try {
            // 重点方法:将得到的pvs委派给InjectionMetadata去处理
            // 下方会单开一个代码块展开梳理里面的逻辑
            metadata.inject(bean, beanName, pvs);
        }
        catch (BeanCreationException ex) {
            throw ex;
        }
        catch (Throwable ex) {
            throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
        }
        // 将最终的pvs返回
        return pvs;
    }

    /**
     * 寻找Class上标注的,需要注入的参数
     * 
     * @param beanName Bean的名称
     * @param clazz    Bean对应的class信息
     * @param pvs      暂存属性值的对象
     */
    private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
        // Fall back to class name as cache key, for backwards compatibility with custom callers.
        // 该方法使用类名作为缓存Key,以此兼容自定义调用者?不太懂这个兼容,待研究
        String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
        // Quick check on the concurrent map first, with minimal locking.
        // 先从缓存中取该类的注入信息,加快寻找速度(反射速度慢)
        InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
        // 判断是否需要刷新缓存中的信息:根据名称获取的Class信息
        // 如果一个Class和一个Bean名冲突,就会得到错误的缓存信息
        if (InjectionMetadata.needsRefresh(metadata, clazz)) {
            // 对整个缓存池加锁,防止读写了脏数据
            synchronized (this.injectionMetadataCache) {
                // 加锁二次读取缓存,解决并发读取缓存出现缓存访问不到的情况
                metadata = this.injectionMetadataCache.get(cacheKey);
                if (InjectionMetadata.needsRefresh(metadata, clazz)) {
                    if (metadata != null) {
                        // 需要刷新就先清除再添加
                        metadata.clear(pvs);
                    }
                    // 重点方法:下方会展开解释,使用class信息构造注入元信息
                    metadata = buildAutowiringMetadata(clazz);
                    // 将查到的信息放入缓存中
                    this.injectionMetadataCache.put(cacheKey, metadata);
                }
            }
        }
        // 返回找到的所有依赖信息
        return metadata;
    }
    /**
     * autowiredAnnotationTypes:当前类{@AutowiredAnnotationBeanPostProcessor}的一个重要字段
     * autowiredAnnotationTypes:用做判断字段/方法是否要进行依赖注入
     * 同样的,也可以往autowiredAnnotationTypes中添加自定义注解,达到扩展Spring的目的
     * autowiredAnnotationTypes默认存储以下值,
     *   ==> Autowired.class
     *   ==> Value.class
     * autowiredAnnotationTypes的初始化在{@link AutowiredAnnotationBeanPostProcessor#AutowiredAnnotationBeanPostProcessor()}无参构造器中
     */
    private final Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(4);

    /**
     * 根据class信息,构建注入元信息
     * 注入元素:需要注入的字段/方法
     * 注入元信息:封装了所有的注入元素,为了给外部使用的
     * 
     * @param clazz 待解析的class信息
     */
    private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {

        // 这个方法把我看懵了,我以为是判断class上有没有this.autowiredAnnotationTypes对应的注解
        // 结果里面判断class和this.autowiredAnnotationTypes是不是java.开头,为什么这么判断?待研究
        if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
            return InjectionMetadata.EMPTY;
        }

        // 最终返回出去的元信息数组
        List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
        // 当前判断的class信息,因为下面要开始递归判断类信息了
        Class<?> targetClass = clazz;

        do {
            // 当前循环的注入元素列表,存储当前循环时得到的注入元素
            final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();

            // 使用反射遍历当前类中的所有DeclaredFields(属于当前类声明的字段),此时是用反射获取类字段信息,所以有顺序
            ReflectionUtils.doWithLocalFields(targetClass, field -> {
            // 会判断当前字段上有没有autowiredAnnotationTypes中包含的注解信息
                MergedAnnotation<?> ann = findAutowiredAnnotation(field);
                if (ann != null) {
                    //判断字段是否是静态的,静态字段直接return,不支持静态字段的注入 
                    if (Modifier.isStatic(field.getModifiers())) {
                        if (logger.isInfoEnabled()) {
                            logger.info("Autowired annotation is not supported on static fields: " + field);
                        }
                        return;
                    }
                    // 判断注解是否有required字段,没有则返回true,有字段,则返回对应的true/false
                    boolean required = determineRequiredStatus(ann);
                    // 创建注入元素(AutowiredFieldElement)并添加到当前循环的元信息列表
                    currElements.add(new AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement(field, required));
                }
            });

            // 使用反射遍历当前类中的所有DeclaredMethods(当前类声明的方法)
            ReflectionUtils.doWithLocalMethods(targetClass, method -> {
                // 判断方法是否是桥接方法,如果不是桥接方法,则进行下面的处理,如果是桥接方法,则我没看懂...待研究
                Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
                if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
                    return;
                }
                // 判断方法是否含有this.autowiredAnnotationTypes中的注解
                MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
                if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
                    // 如果是静态方法,就return,不支持静态方法的注入
                    if (Modifier.isStatic(method.getModifiers())) {
                        if (logger.isInfoEnabled()) {
                            logger.info("Autowired annotation is not supported on static methods: " + method);
                        }
                        return;
                    }
                    // 方法注入理解不深
                    if (method.getParameterCount() == 0) {
                        if (logger.isInfoEnabled()) {
                            logger.info("Autowired annotation should only be used on methods with parameters: " +
                                    method);
                        }
                    }
                    // 判断注解是否有required字段,没有则返回true,有字段,则返回对应的true/false
                    boolean required = determineRequiredStatus(ann);
                    // 寻找方法的属性描述符
                    PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                    // 创建注入元素(AutowiredMethodElement)并添加到当前循环的注入元素列表
                    currElements.add(new AutowiredAnnotationBeanPostProcessor.AutowiredMethodElement(method, required, pd));
                }
            });
            // 将本地存储的元素数组,放到当前类整体的元素数组中
            elements.addAll(0, currElements);
            // 切换判断目标为当前类的父类
            targetClass = targetClass.getSuperclass();
        }
        // class为Object时,退出循环
        while (targetClass != null && targetClass != Object.class);
        // 将注入元素(InjectedElement)封装成注入元信息(InjectionMetadata)并返回给外部使用
        return InjectionMetadata.forElements(elements, clazz);
    }
}

上面梳理了创建注入信息的流程,接下来看看AutowiredAnnotationBeanPostProcessor拿到了注入元信息后,是怎么将注入元信息与PropertiesValues关联起来的

注入元信息源码解析InjectionMetadata#inject

/**
 * 注入元信息的顶层类
 */
public class InjectionMetadata {

    /**
     * postProcessProperties调用此方法时,会将
     * 
     * @param target   注入信息的目标类
     * @param beanName Bean的名称
     * @param pvs      注入属性值
     */
    public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
        // 此处的checkedElements ,就是InjectionMetadata.forElements(elements, clazz)时的elements
        //   ==> 创建InjectionMetadata时,会将elements赋值给内部的injectedElements属性
        //   ==> 在调用`checkConfigMembers`方法时,会将injectedElements赋值给checkedElements
        Collection<InjectedElement> checkedElements = this.checkedElements;
        // 如果没有调用`checkConfigMembers`方法,checkedElements 为空,依然会使用injectedElements参数来遍历处理
        Collection<InjectedElement> elementsToIterate = (checkedElements != null ? checkedElements : this.injectedElements);
        // 开始遍历内部的注入元素
        if (!elementsToIterate.isEmpty()) {
            for (InjectedElement element : elementsToIterate) {
                if (logger.isTraceEnabled()) {
                    logger.trace("Processing injected element of bean '" + beanName + "': " + element);
                }
                // 每个元素执行`inject`方法,处理对应的元素
                //   ==> 此处使用子类`AutowiredFieldElement`来展开梳理
                //   ==> 子类`AutowiredMethodElement`的整理逻辑异曲同工
                element.inject(target, beanName, pvs);
            }
        }
    }
}

前置知识点:注册Bean与Bean依赖关系 DefaultSingletonBeanRegistry 的registerDependentBean()方法对属性注入

字段注入AutowiredFieldElement主要方法解析

public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {

    /**
     * Class representing injection information about an annotated field.
     * 注解字段的类注入信息
     */
    private class AutowiredFieldElement extends InjectionMetadata.InjectedElement {

        // 对应@Autowrite的required属性
        private final boolean required;

        // 判断字段注入元素中的信息是否创建了缓存
        private volatile boolean cached = false;

        // 字段注入元素对应的缓存信息
        @Nullable
        private volatile Object cachedFieldValue;

        // 初始化一下默认值
        public AutowiredFieldElement(Field field, boolean required) {
            super(field, null);
            this.required = required;
        }

    /**
     * 该类的主要职责,根据注入元素信息,获取元素实例
     * 注册Bean与Bean依赖关系:<a href="https://blog.csdn.net/Leon_Jinhai_Sun/article/details/109782537">DefaultSingletonBeanRegistry 的registerDependentBean()方法对属性注入</a>
     * 整个方法通过存储的字段信息,直接生成依赖描述符去BeanFactory中查询是否有对应的Bean
     * 其实忽略了传入的pvs,不对pvs修改也不使用,为什么忽略?有待研究
     * 
     * @param bean     需要注入信息的Bean
     * @param beanName Bean的名称
     * @param pvs      从外部或内部定义的属性信息
     */	
    @Override
    protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
    // this.member里存的是,通过反射拿到的字段信息
        Field field = (Field) this.member;
        Object value;
        // 如果有缓存,就从缓存中拿数据
        if (this.cached) {
            // 因为会有required = false 的情况,所以缓存里会存储依赖描述符(下方有介绍:AutowiredAnnotationBeanPostProcessor.ShortcutDependencyDescriptor)
            //   ==> 如果是依赖描述符,就触发一次依赖处理(beanFactory.resolveDependency)
            //   ==> 如果不是以来描述符,就直接返回缓存值
            value = resolvedCachedArgument(beanName, this.cachedFieldValue);
        }
        else {
            // 使用字段信息创建一个依赖描述符
            DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
            // 设置此依赖的包含Bean ==> 指定这个依赖在申请注入的Bean中
            desc.setContainingClass(bean.getClass());
            // 此处不懂实际用处,待研究
            Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
            // 要使用BeanFactory来查找Bean,所以得判断BeanFactory是否存在
            Assert.state(beanFactory != null, "No BeanFactory available");
            // 获取类型转换器,处理类似String==>Bean的情况
            TypeConverter typeConverter = beanFactory.getTypeConverter();
            try {
                // 进行一次依赖处理,和上方的知识点串起来了,resolveDependency根据依赖描述符获取一个Bean
                value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
            }
            catch (BeansException ex) {
                throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
            }
            // 对当前Bean加锁
            synchronized (this) {
                // 如果当前没有缓存
                if (!this.cached) {
                    // 找到了value 或者 必须注入的情况
                    if (value != null || this.required) {
                        // 就把当前的依赖描述符当做缓存值放着
                        this.cachedFieldValue = desc;
                        // 将Bean与Bean依赖关系注册到注册器中
                        registerDependentBeans(beanName, autowiredBeanNames);
                        // 如果只有一个依赖项
                        if (autowiredBeanNames.size() == 1) {
                            String autowiredBeanName = autowiredBeanNames.iterator().next();
                            // 判断BeanFactory中是否含有此Bean,Bean的类型是否和需要的类型匹配
                            if (beanFactory.containsBean(autowiredBeanName) && beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
                                // 是需要的Bean,则创建依赖的快捷访问方式,并设置为缓存值
                                this.cachedFieldValue = new AutowiredAnnotationBeanPostProcessor.ShortcutDependencyDescriptor( desc, autowiredBeanName, field.getType());
                            }
                        }
                    }
                    else {
                        // 没有找到value时,缓存值为null
                        this.cachedFieldValue = null;
                    }
                    // 切换缓存状态为true,下次再对这个依赖元素判断时,可以取缓存中的值
                    this.cached = true;
                }
            }
        }
        // 如果依赖处理时拿到了Bean,就使用反射的方法对Bean设置值,到了这里,我们的Bean才注入了一个依赖
        if (value != null) {
            ReflectionUtils.makeAccessible(field);
            // 为了走到这一步简直太太太太不容易了!
            field.set(bean, value);
        }
    }
}

JSR-330 @inject注入

注入过程
当classpath中含有JSR-330时,复用AutowiredAnnotationBeanPostProcessor的注入流程

public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {

    /**
     * 很重要的一个类型集合,只有这个集合内的注解才可以使用这个依赖注入流程
     * 使用LinkedHashSet,所以有序,当同一个字段使用多个注入注解时,使用Set中的第一个匹配的注解信息来处理依赖注入
     */
    private final Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(4);

    /**
     * autowiredAnnotationTypes的初始化在构造器中
     * 默认添加了Autowired和Value
     * 需要存在javax.inject.Inject时,才能使用@Inject注解进行依赖注入
     * 同样的,也可以使用往autowiredAnnotationTypes中增加自定义注解,来扩展可注入的类型
     */
    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.
        }
    }
    /**
     * 寻找依赖注入的注解信息
     * 在整个流程中常用的判断,用来获取字段、方法上的注入注解信息,如果没有autowiredAnnotationTypes中的注解,将不会处理依赖注入
     * 
     * @param ao 访问的信息
     */
    @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;
    }
}

Java通用注解:@Resource和@EJB

注入注解,作用类似@Autowired

  • @WebServiceRef
  • @EJB
  • @Resource

生命周期注解,作用类似于BeanPostProcessors

  • @PostConstruct
  • @PreDestroy

Bean的实例化周期执行顺序为

  • @PostConstruct > InitializeBean > 自定义初始化方法

Bean的销毁周期执行顺序为

  • @PreDestroy > DisposableBean > 自定义销毁方法

以上知识点在Spring中的实现,由CommonAnnotationBeanPostProcessor实现,且整体实现逻辑和AutowiredAnnotationBeanPostProcessor差不多,以下摘出部分主要不同点来梳理

/**
 * Java 通用注解的生命周期实现类
 */
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor 
    implements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {
    /**
     * 在构造器中,设置了生命周期初始化与销毁的注解
     * 排序值覆盖 -3
     * AutowiredAnnotationBeanPostProcessor 默认 - 2
     */
    public CommonAnnotationBeanPostProcessor() {
        // 值得注意的是,order值继承于InitDestroyAnnotationBeanPostProcessor
        // InitDestroyAnnotationBeanPostProcessor的排序值默认为最低
        // 但CommonAnnotationBeanPostProcessor将排序值覆盖为(最低-3),也就是倒数第四位执行
        // 而AutowiredAnnotationBeanPostProcessor将排序值默认为(最低-2),也就是倒数第三位执行
        // 说明CommonAnnotationBeanPostProcessor相关的生命周期方法将会优先于AutowiredAnnotationBeanPostProcessor执行
        setOrder(Ordered.LOWEST_PRECEDENCE - 3);
        // 可以通过替换以下两个注解来自定义扩展,但是不推荐
        // 因为这个类是专为Java通用注解做的适配,想自定义推荐使用AutowiredAnnotationBeanPostProcessor进行扩展
        // 设置初始化周期的注解为@PostConstruct
        setInitAnnotationType(PostConstruct.class);
        // 设置销毁周期的注解为@PreDestroy
        setDestroyAnnotationType(PreDestroy.class);
        ignoreResourceType("javax.xml.ws.WebServiceContext");
    }

}

/**
 * CommonAnnotationBeanPostProcessor继承了这个生命周期类
 * 可以从这里看到相关方法定义与设计的细节
 */
public class InitDestroyAnnotationBeanPostProcessor implements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, PriorityOrdered, Serializable {
    /**
     * CommonAnnotationBeanPostProcessor构造器里设置的初始化生命周期注解将会存在这里
     */
    @Nullable
    private Class<? extends Annotation> initAnnotationType;
    /**
     * CommonAnnotationBeanPostProcessor构造器里设置的销毁生命周期注解将会存在这里
     */
    @Nullable
    private Class<? extends Annotation> destroyAnnotationType;
    /**
     * 生命周期排序值默认最低,放在最后处理
     * 但是CommonAnnotationBeanPostProcessor将这个值改成了Ordered.LOWEST_PRECEDENCE - 3
     */
    private int order = Ordered.LOWEST_PRECEDENCE;

    /**
     * 处理合并BeanDefinition的地方
     * 通用注解使用LifecycleMetadata存储注入元素信息
     * 而@Autowired使用的InjectionMetadata存储元素信息
     * 通用注解比@Autowrite多了生命周期相关的逻辑,详细看下方
     */
    @Override
    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
        InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata metadata = findLifecycleMetadata(beanType);
        metadata.checkConfigMembers(beanDefinition);
    }


    /**
     * 这是一个内部类
     * LifecycleMetadata相比InjectionMetadata,增加了生命周期相关的东西
     */
    private class LifecycleMetadata {
        /**
         * 目标Class信息
         */
        private final Class<?> targetClass;
        /**
         * 初始化方法
         */
        private final Collection<LifecycleElement> initMethods;
        /**
         * 销毁方法
         */
        private final Collection<LifecycleElement> destroyMethods;
        /**
         * 经过checkConfigMembers方法的调用
         * checkedInitMethods会等于initMethods
         * 暂不明白为什么这么设计,待研究
         */
        @Nullable
        private volatile Set<LifecycleElement> checkedInitMethods;
        /**
         * 经过checkConfigMembers方法的调用
         * checkedDestroyMethods会等于destroyMethods
         * 暂不明白为什么这么设计,待研究
         */
        @Nullable
        private volatile Set<LifecycleElement> checkedDestroyMethods;
    }

    /**
     * 继续看InitDestroyAnnotationBeanPostProcessor相关的方法细节
     * 现在看一个和{@link AutowiredAnnotationBeanPostProcessor#buildAutowiringMetadata}很类似的方法{@link InitDestroyAnnotationBeanPostProcessor#buildLifecycleMetadata}
     * <b>buildAutowiringMetadata</b>是为了构建依赖注入时的元信息
     * <b>buildLifecycleMetadata</b>是为了构建依赖注入时的生命周期信息
     * 
     * 再次提示:CommonAnnotationBeanPostProcessor继承于InitDestroyAnnotationBeanPostProcessor
     * 于此同时:CommonAnnotationBeanPostProcessor并没有对InitDestroyAnnotationBeanPostProcessor的方法进行很多的重写
     * 所以现在研究InitDestroyAnnotationBeanPostProcessor等同于分析CommonAnnotationBeanPostProcessor
     */
    private InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
        /**
         * 判断方法上是否有指定的注解
         */
        if (!AnnotationUtils.isCandidateClass(clazz, Arrays.asList(this.initAnnotationType, this.destroyAnnotationType))) {
            return this.emptyLifecycleMetadata;
        }

        // 整体的,最终会返回的初始化和销毁方法
        List<InitDestroyAnnotationBeanPostProcessor.LifecycleElement> initMethods = new ArrayList<>();
        List<InitDestroyAnnotationBeanPostProcessor.LifecycleElement> destroyMethods = new ArrayList<>();
        // 由于涉及到循环寻找父类,所以targetClass代表当前循环时判断的类信息
        Class<?> targetClass = clazz;

        do {
            final List<InitDestroyAnnotationBeanPostProcessor.LifecycleElement> currInitMethods = new ArrayList<>();
            final List<InitDestroyAnnotationBeanPostProcessor.LifecycleElement> currDestroyMethods = new ArrayList<>();
            // 由于生命周期回调是针对方法的,所以和`buildAutowiringMetadata`不同
            // 这里使用反射,只查看方法上是否有指定注解
            ReflectionUtils.doWithLocalMethods(targetClass, method -> {
                // 如果携带了初始化注解
                if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
                    // 使用反射得到的方法构造LifecycleElement存储回调函数
                    InitDestroyAnnotationBeanPostProcessor.LifecycleElement element = new InitDestroyAnnotationBeanPostProcessor.LifecycleElement(method);
                    // 将回调函数放入当前循环的列表中
                    currInitMethods.add(element);
                    if (logger.isTraceEnabled()) {
                        logger.trace("Found init method on class [" + clazz.getName() + "]: " + method);
                    }
                // 这里有一个细节点,当判断方法携带了初始化注解时,不会直接continue,而是会继续看是否有销毁注解
                // 所以可以对同一个方法同时标注初始化与销毁注解
                }
                // 如果携带了销毁注解
                if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
                    // 使用反射得到的方法构造LifecycleElement存储回调函数
                    currDestroyMethods.add(new InitDestroyAnnotationBeanPostProcessor.LifecycleElement(method));
                    if (logger.isTraceEnabled()) {
                        logger.trace("Found destroy method on class [" + clazz.getName() + "]: " + method);
                    }
                }
            });

            // 这里又是一个细节点,代表父类的回调函数会优先于子类的执行
            // ==> 调用的是addAll(int index, Collection<? extends E> c);会从index位置开始插入
            // ==> 而不是addAll(Collection<? extends E> c);会添加到列表尾部
            initMethods.addAll(0, currInitMethods);
            // 销毁方法则不同,是添加到了尾部
            // 最终的调用的流程就会呈现为父类初始化 -> 子类初始化 -> 子类销毁 -> 父类销毁
            // 这么一想很有道理了,父类包着子类,像两个同心圆一样
            destroyMethods.addAll(currDestroyMethods);
            // 切换判断的class
            targetClass = targetClass.getSuperclass();
        }
        // 当类为Object时,停止循环
        while (targetClass != null && targetClass != Object.class);

        // 没有数据就返回空的默认实现,有就合成LifecycleMetadata返回出去
        return (initMethods.isEmpty() && destroyMethods.isEmpty() ? this.emptyLifecycleMetadata : new InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata(clazz, initMethods, destroyMethods));
    }
}

CommonAnnotationBeanPostProcessorAutowiredAnnotationBeanPostProcessor整体的设计思路是一致的,代码复用性极强,并且还做了生命周期的扩展。

最简化自定义依赖注入注解

如何使用自定义注解,实现依赖注入?

方向一:基于AutowiredAnnotationBeanPostProcessor实现

  • 方案一:元标注@Autowired
  • 方案二:扩展容器内的AutowiredAnnotationBeanPostProcessor

方向二:自定义类实现生命周期接口
需要实现以下接口并在Bean实例化之前,注册到AbstractBeanFactory

  • 生命周期
    • InstantiationAwareBeanPostProcessor
    • MergedBeanDefinitionPostProcessor
  • 元数据
    • InjectedElement
    • InjectionMetadata

方案一:元标注@Autowired

/**
 * 通过对自定义注解进行元标注@Autowired的方式实现自定义注解
 * 其实在限定注入内容里,就介绍了@Qualifer和@LoadBalance的实现原理,也是因为元标注了@Autowired
 */
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Autowired
public @interface MateInject {
    /**
     * 因为注解不能继承,所以这里显示定义一个required
     * 当然,不显示定义也可以,在上面的梳理中解释了
     * 在{@link AutowiredAnnotationBeanPostProcessor#determineRequiredStatus}的判断中,如果没有这个字段,就代表为true
     */
    boolean required() default true;
}

这时候直接使用这个注解,就能实现依赖注入了,就那么简单~

方案二:扩展容器内的AutowiredAnnotationBeanPostProcessor

/**
 * 首先创建一个自定义的注解
 * 和@Autowired没什么关系
 */
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CustomInject {
}

public class Demo {

    /**
     * 使用静态方法,注入一个`AutowiredAnnotationBeanPostProcessor`当做生命周期流程Bean
     * 这时候@Bean的name字段有两种选择
     * ==> 选择一:使用{@link AnnotationConfigUtils#AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME}
     *   ==> 这时候Spring默认的`AutowiredAnnotationBeanPostProcessor`将不会注入,只能处理方法内定义的注解
     * ==> 选择二:使用自定义名称(不等于上方特殊字段的值),这时将只做扩展,不会影响Spring默认的注入规则
     * 通常使用选择二,只对Spring做扩展
     */
    @Bean(name = AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME) // 选择一
    @Bean(name = "InjectUserBeanPostProcessor")            // 选择二
    /**
     * 使用@order,可以控制注入流程的执行顺序
     */
    @Order(Ordered.LOWEST_PRECEDENCE - 4) 
    public static AutowiredAnnotationBeanPostProcessor beanPostProcessor() {
        AutowiredAnnotationBeanPostProcessor beanPostProcessor = new AutowiredAnnotationBeanPostProcessor();
        // 可以单独设置一个注解为注入注解
         beanPostProcessor.setAutowiredAnnotationType(InjectedUser.class);
        // 也可以通过传入一个Set设置多个注解为注入注解,是否需要有序看自己需求了
        Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(asList(CustomInject.class));
        beanPostProcessor.setAutowiredAnnotationTypes(autowiredAnnotationTypes);
        // 返回自定义依赖注入流程
        return beanPostProcessor;
    }

}

一点问题

有多少种依赖注入的方式

  • 构造器注入
  • 字段注入
  • Setter注入
  • 方法注入
  • 接口回调注入

偏好构造器注入还是字段注入?

  • 没有最好,只有相对合理
  • 两种都可以,强制依赖推荐构造器注入,可选依赖推荐字段注入

为什么有的Bean无法通过依赖查找获取,但能通过依赖注入获取?

  • Spring 注入来源问题
  • 突破点:依赖查找使用getBean操作,依赖注入使用resolveDependency操作
  • 待续…
0

评论区