依赖注入的模式和类型

模式

手动模式

配置或者编程的方式:

  1. XML 资源配置元信息(常用)
  2. Java 注解配置元信息(常用)
  3. API 配置元信息

    自动模式

    实现方提供依赖自动关联的方式,按照内建的注入规则:
    Autowiring(自动绑定)

    类型

    Setter 方法:<proeprty name= "user" ref= "userBean" />

构造器:<constructor-arg name="user" ref="userBean" />

字段:@Autowired User user;

方法:@Autowired User user;

接口回调:class MyBean implements BeanFactoryAware { ... }

自动绑定(Autowiring)

官方说明

The Spring container can autowire relationships between collaborating beans. You can let Spring resolve collaborators (other beans) automatically for your bean by inspecting the contents of the ApplicationContext.

Spring 容器可以自动关联依赖 Bean 和被依赖 Bean,可以通过检查 ApplicationContext 的内容来让 Spring 自动解析依赖 Bean 的关系。

优点

Autowiring can significantly reduce the need to specify properties or constructor arguments.

自动绑定可以显著减少指定属性或构造器的需要,比如下述代码:

  1. <bean id="user" class="com.mindartisan.spring.geek.ioc.overview.domain.User">
  2. <property name="id" value="1"/>
  3. <property name="name" value="Steve"/>
  4. </bean>

如果我将 value="Steve"变成到 ref="myName"这个 Bean,此时 myName 这个 Bean 就会关联到 name 属性上。

如果此时有个名称是 name 的bean,我可以将 <property name="name" value="Steve"/>注释掉,然后再在<bean id="user" class="com.mindartisan.spring.geek.ioc.overview.domain.User"> 添加 autowire="byName,此时 name 这个 Bean 会被自动装配到 name 属性中。

注意:一般显性绑定比较好,如果某 Bean 的属性字段名称变化,此时按名称找的话,找不到(比如 name -> newName,此时没有名称是 newName 的 Bean。

Autowiring can update a configuration as your objects evolve.

随着对象的更新,自动装配可以自动更新配置(这其实是和 Java 语言特性相关,传引用的类型。)

自动绑定(Autowiring)模式

模式 说明 备注
no 默认值,不使用自动绑定,需要手动指定依赖注入对象
byName 根据被注入属性的名称作为 Bean 名称进行依赖查找, 并将对象设置到该属性。
byType 根据被注入属性的类型作为依赖类型进行查找, 并将对象设置到该属性。 有多个相同 type 的 bean 的情况下,可以使用 @Primary注解来设置优先级
constructor 特殊 byType 类型, 用于构造器参数

具体代码,参照 Autowire此枚举:

  1. public enum Autowire {
  2. /**
  3. * Constant that indicates no autowiring at all.
  4. */
  5. NO(AutowireCapableBeanFactory.AUTOWIRE_NO),
  6. /**
  7. * Constant that indicates autowiring bean properties by name.
  8. */
  9. BY_NAME(AutowireCapableBeanFactory.AUTOWIRE_BY_NAME),
  10. /**
  11. * Constant that indicates autowiring bean properties by type.
  12. */
  13. BY_TYPE(AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE);
  14. private final int value;
  15. Autowire(int value) {
  16. this.value = value;
  17. }
  18. public int value() {
  19. return this.value;
  20. }
  21. /**
  22. * Return whether this represents an actual autowiring value.
  23. * @return whether actual autowiring was specified
  24. * (either BY_NAME or BY_TYPE)
  25. */
  26. public boolean isAutowire() {
  27. return (this == BY_NAME || this == BY_TYPE);
  28. }
  29. }

具体的可以看 AutowireCapableBeanFactory此类,规定了以下几种:

  1. int AUTOWIRE_NO = 0;
  2. int AUTOWIRE_BY_NAME = 1;
  3. int AUTOWIRE_BY_TYPE = 2;
  4. int AUTOWIRE_CONSTRUCTOR = 3;
  5. @Deprecated
  6. int AUTOWIRE_AUTODETECT = 4;

自动绑定(Autowiring)限制和不足

限制不足

官方文档:

  • Explicit dependencies in property and constructor-arg settings always override autowiring. You cannot autowire simple properties such as primitives, Strings, and Classes (and arrays of such simple properties). This limitation is by-design.
  • Autowiring is less exact than explicit wiring. Although, as noted in the earlier table, Spring is careful to avoid guessing in case of ambiguity that might have unexpected results. The relationships between your Spring-managed objects are no longer documented explicitly.
  • Wiring information may not be available to tools that may generate documentation from a Spring container.
  • Multiple bean definitions within the container may match the type specified by the setter method or constructor argument to be autowired. For arrays, collections, or Map instances, this is not necessarily a problem. However, for dependencies that expect a single value, this ambiguity is not arbitrarily resolved. If no unique bean definition is available, an exception is thrown.

    —— Limitations and Disadvantages of Autowiring

个人理解:

  1. 更准确的 propertyconstructor-arg会覆盖掉自动绑定。不能自动绑定一些简单的属性,比如原生类型、String 类型、Class 类型,这是设计上的限制。咱们自动绑定的时候,会去绑定一个 Bean 或者引用对象,原生类型没法声明成一个 Bean。
  2. 自动装配不如显式绑定准确。Spring 对于可能产生歧义的产生意料之外结果的猜测要尽量避免(这里可以理解为你绑定属性的时候,对应要绑定 bean 名称写错了。比如你要将一个类的 User 的属性绑定为 SuperUser 这个 bean,但是你手误写成了 User 这个 bean)
  3. 绑定的相关信息没法在工具中提示,比如从 Spring 容器中生成对应的容器(我理解的是不知道容器里有没有想要绑定的 Bean)
  4. 如果应用上下文中有多个 bean 的定义,byType 的时候不知道绑定哪个,会抛异常。

    对应方案

    官方文档:
    • Abandon autowiring in favor of explicit wiring.
    • Avoid autowiring for a bean definition by setting its autowire-candidate attributes to false, as described in the next section.
    • Designate a single bean definition as the primary candidate by setting the primary attribute of its element to true.
    • Implement the more fine-grained control available with annotation-based configuration, as described in Annotation-based Container Configuration.—— Limitations and Disadvantages of Autowiring

个人理解:

  1. 你可以放弃这种方式
  2. autowire-candidate改为 false
  3. 有多个相同类型 Bean 的时候,用 @primary 注解标注
  4. 如果想更细粒度控制,用注解的方式

    Setter 方法依赖注入

    手动方式

  5. XML 资源配置元信息

  6. Java 注解配置元信息
  7. API 配置元信息

相关代码:
XmlDependencySetterInjectionDemo.class

  1. /**
  2. * 基于 xml 资源的依赖 setter 方法注入示例
  3. *
  4. * @author mindartisan.blog.csdn.net
  5. * @date
  6. */
  7. public class XmlDependencySetterInjectionDemo {
  8. public static void main(String[] args) {
  9. DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
  10. XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory);
  11. String xmlResourcePath = "classpath:/META-INF/dependency-setter-injection.xml";
  12. // 加载 XML 资源,解析并生成 BeanDefinition
  13. xmlBeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
  14. // 依赖查找并创建 Bean
  15. UserHolder userHolder = defaultListableBeanFactory.getBean(UserHolder.class);
  16. System.out.println(userHolder);
  17. }
  18. }

dependency-setter-injection.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5. <import resource="classpath:/META-INF/dependency-lookup-context.xml"/>
  6. <bean class="com.mindartisan.spring.geek.ioc.dependency.injection.UserHolder">
  7. <!-- 会关联到 id =1,name = Steve 的 bean -->
  8. <property name="user" ref="user"/>
  9. <!-- 同理 -->
  10. <!--<property name="user" ref="superUser"/>-->
  11. </bean>
  12. </beans>

AnnotationDependencySetterInjectionDemo.class

  1. /**
  2. * 基于注解的依赖 setter 方法注入示例
  3. *
  4. * @author mindartisan.blog.csdn.net
  5. * @date
  6. */
  7. public class AnnotationDependencySetterInjectionDemo {
  8. public static void main(String[] args) {
  9. // 创建 BeanFactory 容器
  10. AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
  11. // 注册 配置类
  12. applicationContext.register(AnnotationDependencySetterInjectionDemo.class);
  13. // 将 User Bean 初始化,供 userHolder(User user) 使用
  14. XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
  15. String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
  16. // 加载 XML 资源,解析并生成 BeanDefinition
  17. xmlBeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
  18. // 启动 Spring 应用上下文
  19. applicationContext.refresh();
  20. UserHolder userHolder = applicationContext.getBean(UserHolder.class);
  21. System.out.println(userHolder);
  22. // 关闭 Spring 应用上下文
  23. applicationContext.close();
  24. }
  25. // /**
  26. // * 此处采用的构造器方式
  27. // *
  28. // * @param user 用户
  29. // * @return {@link UserHolder}
  30. // */
  31. @Bean
  32. public UserHolder userHolder(User user) {
  33. return new UserHolder(user);
  34. }
  35. /**
  36. * 此处采用 setter 方式
  37. *
  38. * @param user 用户
  39. * @return {@link UserHolder}
  40. */
  41. // @Bean
  42. // public UserHolder userHolder(User user) {
  43. // UserHolder userHolder = new UserHolder();
  44. // userHolder.setUser(user);
  45. // return userHolder;
  46. // }
  47. }

dependency-lookup-context.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5. <bean id="user" class="com.mindartisan.spring.geek.ioc.overview.domain.User" autowire="byName">
  6. <property name="id" value="1"/>
  7. <property name="name" value="Steve"/>
  8. </bean>
  9. <bean id="superUser" class="com.mindartisan.spring.geek.ioc.overview.domain.SuperUser" parent="user"
  10. primary="true">
  11. <property name="address" value="北京"/>
  12. </bean>
  13. <!-- 延迟查找使用 -->
  14. <bean id="objectFactoryCreatingFactoryBean"
  15. class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
  16. <property name="targetBeanName" value="user"/>
  17. </bean>
  18. </beans>

ApiDependencySetterInjectionDemo.class

  1. /**
  2. * 基于 API 实现依赖 setter 方法注入示例
  3. *
  4. * @author mindartisan.blog.csdn.net
  5. * @date
  6. */
  7. public class ApiDependencySetterInjectionDemo {
  8. public static void main(String[] args) {
  9. // 创建 BeanFactory 容器
  10. AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
  11. // 注册 UserHolder 的 BeanDefinition
  12. BeanDefinition userHolderBeanDefinition = createUserHolderBeanDefinition();
  13. applicationContext.registerBeanDefinition("userHolder", userHolderBeanDefinition);
  14. // 将 User Bean 初始化
  15. XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
  16. String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
  17. // 加载 XML 资源,解析并生成 BeanDefinition
  18. xmlBeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
  19. // 启动 Spring 应用上下文
  20. applicationContext.refresh();
  21. UserHolder userHolder = applicationContext.getBean(UserHolder.class);
  22. System.out.println(userHolder);
  23. // 关闭 Spring 应用上下文
  24. applicationContext.close();
  25. }
  26. /**
  27. * 为 UserHolder 生成 BeanDefinition
  28. *
  29. * @return {@link BeanDefinition}
  30. */
  31. private static BeanDefinition createUserHolderBeanDefinition() {
  32. // API 用的就是下述代码
  33. BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserHolder.class);
  34. // 类似 xml 文件中 「ref=""」
  35. beanDefinitionBuilder.addPropertyReference("user", "superUser");
  36. AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
  37. return beanDefinition;
  38. }
  39. }

dependency-lookup-context.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5. <bean id="user" class="com.mindartisan.spring.geek.ioc.overview.domain.User" autowire="byName">
  6. <property name="id" value="1"/>
  7. <property name="name" value="Steve"/>
  8. </bean>
  9. <bean id="superUser" class="com.mindartisan.spring.geek.ioc.overview.domain.SuperUser" parent="user"
  10. primary="true">
  11. <property name="address" value="北京"/>
  12. </bean>
  13. <!-- 延迟查找使用 -->
  14. <bean id="objectFactoryCreatingFactoryBean"
  15. class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
  16. <property name="targetBeanName" value="user"/>
  17. </bean>
  18. </beans>

自动方式

  1. byName
  2. byType

相关代码:
AutoWiringByNameDependencySetterInjectionDemo.class

  1. /**
  2. * byName Autowiring 依赖 setter 方法注释示例
  3. *
  4. * @author mindartisan.blog.csdn.net
  5. * @date
  6. */
  7. public class AutoWiringByNameDependencySetterInjectionDemo {
  8. public static void main(String[] args) {
  9. DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
  10. XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory);
  11. String xmlResourcePath = "classpath:/META-INF/autowiring-dependency-setter-injection.xml";
  12. // 加载 XML 资源,解析并生成 BeanDefinition
  13. xmlBeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
  14. // 依赖查找并创建 Bean
  15. UserHolder userHolder = defaultListableBeanFactory.getBean(UserHolder.class);
  16. System.out.println(userHolder);
  17. }
  18. }

autowiring-dependency-setter-injection.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5. <import resource="classpath:/META-INF/dependency-lookup-context.xml"/>
  6. <!-- 如果 autowire = "byType",此时会有两个 type 相同的 bean,但是会关联到 superUser,因为 superUser 设置了 primary-->
  7. <bean class="com.mindartisan.spring.geek.ioc.dependency.injection.UserHolder" autowire="byName">
  8. <!-- 会关联到 id =1,name = Steve 的 bean -->
  9. <!--<property name="user" ref="user"/>-->
  10. </bean>
  11. </beans>

构造器依赖注入

手动方式

  1. XML 资源配置元信息
  2. Java 注解配置元信息
  3. API 配置元信息

相关代码:
XmlDependencyConstructorInjectionDemo.class

  1. /**
  2. * 基于 xml 资源的依赖 Constructor 注入示例
  3. *
  4. * @author mindartisan.blog.csdn.net
  5. * @date
  6. */
  7. public class XmlDependencyConstructorInjectionDemo {
  8. public static void main(String[] args) {
  9. DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
  10. XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory);
  11. String xmlResourcePath = "classpath:/META-INF/dependency-constructor-injection.xml";
  12. // 加载 XML 资源,解析并生成 BeanDefinition
  13. xmlBeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
  14. // 依赖查找并创建 Bean
  15. UserHolder userHolder = defaultListableBeanFactory.getBean(UserHolder.class);
  16. System.out.println(userHolder);
  17. }
  18. }

dependency-constructor-injection.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5. <import resource="classpath:/META-INF/dependency-lookup-context.xml"/>
  6. <bean class="com.mindartisan.spring.geek.ioc.dependency.injection.UserHolder">
  7. <!-- 会关联到 id =1,name = Steve 的 bean -->
  8. <constructor-arg name="user" ref="superUser"/>
  9. </bean>
  10. </beans>

AnnotationDependencyConstructorInjectionDemo.class

  1. /**
  2. * 基于注解的依赖 Constructor 注入示例
  3. *
  4. * @author mindartisan.blog.csdn.net
  5. * @date
  6. */
  7. public class AnnotationDependencyConstructorInjectionDemo {
  8. public static void main(String[] args) {
  9. // 创建 BeanFactory 容器
  10. AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
  11. // 注册 配置类
  12. applicationContext.register(AnnotationDependencyConstructorInjectionDemo.class);
  13. // 将 User Bean 初始化,供 userHolder(User user) 使用
  14. XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
  15. String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
  16. // 加载 XML 资源,解析并生成 BeanDefinition
  17. xmlBeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
  18. // 启动 Spring 应用上下文
  19. applicationContext.refresh();
  20. UserHolder userHolder = applicationContext.getBean(UserHolder.class);
  21. System.out.println(userHolder);
  22. // 关闭 Spring 应用上下文
  23. applicationContext.close();
  24. }
  25. // /**
  26. // * 此处采用的构造器方式
  27. // *
  28. // * @param user 用户
  29. // * @return {@link UserHolder}
  30. // */
  31. @Bean
  32. public UserHolder userHolder(User user) {
  33. return new UserHolder(user);
  34. }
  35. /**
  36. * 此处采用 setter 方式
  37. *
  38. * @param user 用户
  39. * @return {@link UserHolder}
  40. */
  41. // @Bean
  42. // public UserHolder userHolder(User user) {
  43. // UserHolder userHolder = new UserHolder();
  44. // userHolder.setUser(user);
  45. // return userHolder;
  46. // }
  47. }

dependency-lookup-context.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5. <bean id="user" class="com.mindartisan.spring.geek.ioc.overview.domain.User" autowire="byName">
  6. <property name="id" value="1"/>
  7. <property name="name" value="Steve"/>
  8. </bean>
  9. <bean id="superUser" class="com.mindartisan.spring.geek.ioc.overview.domain.SuperUser" parent="user"
  10. primary="true">
  11. <property name="address" value="北京"/>
  12. </bean>
  13. <!-- 延迟查找使用 -->
  14. <bean id="objectFactoryCreatingFactoryBean"
  15. class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
  16. <property name="targetBeanName" value="user"/>
  17. </bean>
  18. </beans>

ApiDependencyConstructorInjectionDemo.class

  1. /**
  2. * 基于 API 实现依赖 Constructor 注入示例
  3. *
  4. * @author mindartisan.blog.csdn.net
  5. * @date
  6. */
  7. public class ApiDependencyConstructorInjectionDemo {
  8. public static void main(String[] args) {
  9. // 创建 BeanFactory 容器
  10. AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
  11. // 注册 UserHolder 的 BeanDefinition
  12. BeanDefinition userHolderBeanDefinition = createUserHolderBeanDefinition();
  13. applicationContext.registerBeanDefinition("userHolder", userHolderBeanDefinition);
  14. // 将 User Bean 初始化
  15. XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
  16. String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
  17. // 加载 XML 资源,解析并生成 BeanDefinition
  18. xmlBeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
  19. // 启动 Spring 应用上下文
  20. applicationContext.refresh();
  21. UserHolder userHolder = applicationContext.getBean(UserHolder.class);
  22. System.out.println(userHolder);
  23. // 关闭 Spring 应用上下文
  24. applicationContext.close();
  25. }
  26. /**
  27. * 为 UserHolder 生成 BeanDefinition
  28. *
  29. * @return {@link BeanDefinition}
  30. */
  31. private static BeanDefinition createUserHolderBeanDefinition() {
  32. // API 用的就是下述代码
  33. BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserHolder.class);
  34. // 类似 xml 文件中 「constructor-arg」
  35. beanDefinitionBuilder.addConstructorArgReference("superUser");
  36. AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
  37. return beanDefinition;
  38. }
  39. }

dependency-lookup-context.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5. <bean id="user" class="com.mindartisan.spring.geek.ioc.overview.domain.User" autowire="byName">
  6. <property name="id" value="1"/>
  7. <property name="name" value="Steve"/>
  8. </bean>
  9. <bean id="superUser" class="com.mindartisan.spring.geek.ioc.overview.domain.SuperUser" parent="user"
  10. primary="true">
  11. <property name="address" value="北京"/>
  12. </bean>
  13. <!-- 延迟查找使用 -->
  14. <bean id="objectFactoryCreatingFactoryBean"
  15. class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
  16. <property name="targetBeanName" value="user"/>
  17. </bean>
  18. </beans>

自动方式

  1. constructor

相关代码:
AutoWiringConstructorDependencyConstructorInjectionDemo.class

  1. /**
  2. * byName Autowiring 依赖 Constructor 注入示例
  3. *
  4. * @author mindartisan.blog.csdn.net
  5. * @date
  6. */
  7. public class AutoWiringConstructorDependencyConstructorInjectionDemo {
  8. public static void main(String[] args) {
  9. DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
  10. XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory);
  11. String xmlResourcePath = "classpath:/META-INF/autowiring-dependency-constructor-injection.xml";
  12. // 加载 XML 资源,解析并生成 BeanDefinition
  13. xmlBeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
  14. // 依赖查找并创建 Bean
  15. UserHolder userHolder = defaultListableBeanFactory.getBean(UserHolder.class);
  16. System.out.println(userHolder);
  17. }
  18. }

autowiring-dependency-constructor-injection.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5. <import resource="classpath:/META-INF/dependency-lookup-context.xml"/>
  6. <bean class="com.mindartisan.spring.geek.ioc.dependency.injection.UserHolder" autowire="constructor">
  7. </bean>
  8. </beans>

字段注入

手动模式

  1. @Autowired
  2. @Resource
  3. @Inject(可选)

相关代码:
AnnotationDependencyFieldInjectionDemo.class

  1. /**
  2. * 基于注解的依赖 字段 注入示例
  3. *
  4. * @author mindartisan.blog.csdn.net
  5. * @date
  6. */
  7. public class AnnotationDependencyFieldInjectionDemo {
  8. @Autowired
  9. private
  10. // static // 会忽略掉静态字段
  11. UserHolder userHolder;
  12. @Resource// 静态字段直接报错
  13. private UserHolder userHolder2;
  14. public static void main(String[] args) {
  15. // 创建 BeanFactory 容器
  16. AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
  17. // 注册 配置类(配置类也是 Spring 的 Bean)
  18. applicationContext.register(AnnotationDependencyFieldInjectionDemo.class);
  19. // 将 User Bean 初始化,供 userHolder(User user) 使用
  20. XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
  21. String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
  22. // 加载 XML 资源,解析并生成 BeanDefinition
  23. xmlBeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
  24. // 启动 Spring 应用上下文
  25. applicationContext.refresh();
  26. // 依赖查找 AnnotationDependencyFieldInjectionDemo bean
  27. AnnotationDependencyFieldInjectionDemo demoBean = applicationContext.getBean(AnnotationDependencyFieldInjectionDemo.class);
  28. // 通过 @Autowired 将字段关联
  29. UserHolder userHolder = demoBean.userHolder;
  30. System.out.println(userHolder);
  31. UserHolder userHolder2 = demoBean.userHolder2;
  32. System.out.println(userHolder2);
  33. // 单例情况下,两个相同,true
  34. System.out.println(userHolder2 == userHolder);
  35. // 关闭 Spring 应用上下文
  36. applicationContext.close();
  37. }
  38. @Bean
  39. public UserHolder userHolder(User user) {
  40. return new UserHolder(user);
  41. }
  42. }

dependency-lookup-context.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5. <bean id="user" class="com.mindartisan.spring.geek.ioc.overview.domain.User" autowire="byName">
  6. <property name="id" value="1"/>
  7. <property name="name" value="Steve"/>
  8. </bean>
  9. <bean id="superUser" class="com.mindartisan.spring.geek.ioc.overview.domain.SuperUser" parent="user"
  10. primary="true">
  11. <property name="address" value="北京"/>
  12. </bean>
  13. <!-- 延迟查找使用 -->
  14. <bean id="objectFactoryCreatingFactoryBean"
  15. class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
  16. <property name="targetBeanName" value="user"/>
  17. </bean>
  18. </beans>

方法注入

手动注入

  1. @Autowired
  2. @Resource
  3. @Inject(可选)
  4. @Bean

相关代码:
AnnotationDependencyMethodInjectionDemo.class

  1. /**
  2. * 基于注解的依赖 方法 注入示例
  3. *
  4. * @author mindartisan.blog.csdn.net
  5. * @date
  6. */
  7. public class AnnotationDependencyMethodInjectionDemo {
  8. private UserHolder userHolder;
  9. private UserHolder userHolder2;
  10. @Autowired
  11. public void method1(UserHolder userHolder) {
  12. this.userHolder = userHolder;
  13. }
  14. @Resource
  15. public void method2(UserHolder userHolder) {
  16. this.userHolder2 = userHolder;
  17. }
  18. @Bean
  19. public UserHolder userHolder(User user) {
  20. return new UserHolder(user);
  21. }
  22. public static void main(String[] args) {
  23. // 创建 BeanFactory 容器
  24. AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
  25. // 注册 配置类(配置类也是 Spring 的 Bean)
  26. applicationContext.register(AnnotationDependencyMethodInjectionDemo.class);
  27. // 将 User Bean 初始化,供 userHolder(User user) 使用
  28. XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
  29. String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
  30. // 加载 XML 资源,解析并生成 BeanDefinition
  31. xmlBeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
  32. // 启动 Spring 应用上下文
  33. applicationContext.refresh();
  34. // 依赖查找 AnnotationDependencyFieldInjectionDemo bean
  35. AnnotationDependencyMethodInjectionDemo demoBean = applicationContext.getBean(AnnotationDependencyMethodInjectionDemo.class);
  36. // 通过 @Autowired 将字段关联
  37. UserHolder userHolder = demoBean.userHolder;
  38. System.out.println(userHolder);
  39. UserHolder userHolder2 = demoBean.userHolder2;
  40. System.out.println(userHolder2);
  41. // 单例情况下,两个相同,true
  42. System.out.println(userHolder2 == userHolder);
  43. // 关闭 Spring 应用上下文
  44. applicationContext.close();
  45. }
  46. }

dependency-lookup-context.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5. <bean id="user" class="com.mindartisan.spring.geek.ioc.overview.domain.User" autowire="byName">
  6. <property name="id" value="1"/>
  7. <property name="name" value="Steve"/>
  8. </bean>
  9. <bean id="superUser" class="com.mindartisan.spring.geek.ioc.overview.domain.SuperUser" parent="user"
  10. primary="true">
  11. <property name="address" value="北京"/>
  12. </bean>
  13. <!-- 延迟查找使用 -->
  14. <bean id="objectFactoryCreatingFactoryBean"
  15. class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
  16. <property name="targetBeanName" value="user"/>
  17. </bean>
  18. </beans>

回调注入

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 对象,用于占位符处理

相关代码:
AwarelnterfaceDependencyInjectionDemo.class

  1. /**
  2. * 基于 Aware 接口回调的依赖注入示例
  3. *
  4. * @author mindartisan.blog.csdn.net
  5. * @date
  6. */
  7. public class AwarelnterfaceDependencyInjectionDemo implements BeanFactoryAware, ApplicationContextAware {
  8. private static BeanFactory beanFactory;
  9. private static ApplicationContext applicationContext;
  10. public static void main(String[] args) {
  11. // 创建 BeanFactory 容器
  12. AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
  13. // 注册 配置类
  14. context.register(AwarelnterfaceDependencyInjectionDemo.class);
  15. // 启动 Spring 应用上下文
  16. context.refresh();
  17. System.out.println(beanFactory == context.getBeanFactory());
  18. System.out.println(applicationContext == context);
  19. // 关闭 Spring 应用上下文
  20. context.close();
  21. }
  22. @Override
  23. public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
  24. AwarelnterfaceDependencyInjectionDemo.beanFactory = beanFactory;
  25. }
  26. @Override
  27. public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
  28. AwarelnterfaceDependencyInjectionDemo.applicationContext = applicationContext;
  29. }
  30. }

依赖注入类型选择

低依赖: 构造器注入,如果构造器的参数过多就不适合使用构造器注入
多依赖:Setter 方法注入,注入的时间顺序依赖与用户操作,如果字段或者依赖的属性存在依赖关系,可能会有问题
便利性:字段注入
声明类:方法注入,一般使用 @Bean 方法注入

基础类型注入

原生类型(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 等

相关代码:
UserForBasicInject.class

  1. /**
  2. * 用户--用于演示基本类型注入
  3. *
  4. * @author mindartisan.blog.csdn.net
  5. * @date
  6. */
  7. public class UserForBasicInject {
  8. private Long id;
  9. private String name;
  10. private City city;
  11. // City 和 Resource 相关用于演示基本类型注入
  12. public City getCity() {
  13. return city;
  14. }
  15. public void setCity(City city) {
  16. this.city = city;
  17. }
  18. private Resource configFileLocation;
  19. public Resource getConfigFileLocation() {
  20. return configFileLocation;
  21. }
  22. public void setConfigFileLocation(Resource configFileLocation) {
  23. this.configFileLocation = configFileLocation;
  24. }
  25. @Override
  26. public String toString() {
  27. return "User{" +
  28. "id=" + id +
  29. ", name='" + name + '\'' +
  30. ", city=" + city +
  31. ", configFileLocation=" + configFileLocation +
  32. '}';
  33. }
  34. public Long getId() {
  35. return id;
  36. }
  37. public void setId(Long id) {
  38. this.id = id;
  39. }
  40. public String getName() {
  41. return name;
  42. }
  43. public void setName(String name) {
  44. this.name = name;
  45. }
  46. // @Override
  47. // public String toString() {
  48. // return "User{" +
  49. // "id=" + id +
  50. // ", name='" + name + '\'' +
  51. // '}';
  52. // }
  53. /**
  54. * 通过静态方法实例化
  55. *
  56. * @return {@link UserForBasicInject}
  57. */
  58. public static UserForBasicInject createUser(){
  59. UserForBasicInject user = new UserForBasicInject();
  60. user.setId(1L);
  61. user.setName("Steve");
  62. return user;
  63. }
  64. }

City.class

  1. /**
  2. * 城市--用来作为 User 属性演示基本类型注入
  3. *
  4. * @author mindartisan.blog.csdn.net
  5. * @date
  6. */
  7. public enum City {
  8. BEIJING,
  9. SHANGHAI,
  10. GUANGZHOU
  11. }

dependency-lookup-context-basic-inject.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5. <bean id="userForBasicInject" class="com.mindartisan.spring.geek.ioc.overview.domain.UserForBasicInject" autowire="byName">
  6. <property name="id" value="1"/>
  7. <property name="name" value="Steve"/>
  8. <!--City 和 configFileLocation 用于演示基本类型注入-->
  9. <property name="city" value="BEIJING"/>
  10. <property name="configFileLocation" value="classpath:/META-INF/user-config.properties"/>
  11. </bean>
  12. <bean id="superUserForBasicInject" class="com.mindartisan.spring.geek.ioc.overview.domain.SuperUserForBasicInject" parent="userForBasicInject"
  13. primary="true">
  14. <property name="address" value="北京"/>
  15. </bean>
  16. <!--延迟查找使用-->
  17. <bean id="objectFactoryCreatingFactoryBean"
  18. class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
  19. <property name="targetBeanName" value="userForBasicInject"/>
  20. </bean>
  21. </beans>

DependencyLookUpDemoForBasicInject.class

  1. /**
  2. * 依赖查找示例--用于演示基础类型注入
  3. *
  4. * @author mindartisan.blog.csdn.net
  5. * @date
  6. */
  7. public class DependencyLookUpDemoForBasicInject {
  8. public static void main(String[] args) {
  9. // 配置 XML 配置文件,两个方式均可
  10. // 启动 Spring 应用上下文
  11. BeanFactory beanFactory = new ClassPathXmlApplicationContext("META-INF/dependency-lookup-context-basic-inject.xml");
  12. // BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/dependency-lookup-context.xml");
  13. lookupInRealTime(beanFactory);
  14. lookupInLazy(beanFactory);
  15. lookupSingleByType(beanFactory);
  16. lookupCollectionByType(beanFactory);
  17. lookupByAnnotationType(beanFactory);
  18. }
  19. /**
  20. * 通过名称:实时查找
  21. *
  22. * @param beanFactory bean工厂
  23. */
  24. private static void lookupInRealTime(BeanFactory beanFactory) {
  25. UserForBasicInject user = (UserForBasicInject) beanFactory.getBean("userForBasicInject");
  26. System.out.println("通过名称,实时查找:" + user);
  27. }
  28. /**
  29. * 通过名称:延迟查找
  30. *
  31. * @param beanFactory bean工厂
  32. */
  33. private static void lookupInLazy(BeanFactory beanFactory) {
  34. ObjectFactory<UserForBasicInject> objectFactoryCreatingFactoryBean = (ObjectFactory<UserForBasicInject>) beanFactory.getBean("objectFactoryCreatingFactoryBean");
  35. UserForBasicInject user = objectFactoryCreatingFactoryBean.getObject();
  36. System.out.println("通过名称,延迟查找:" + user);
  37. }
  38. /**
  39. * 按类型查找:单个 bean
  40. *
  41. * @param beanFactory bean工厂
  42. */
  43. private static void lookupSingleByType(BeanFactory beanFactory) {
  44. UserForBasicInject user = beanFactory.getBean(UserForBasicInject.class);
  45. System.out.println("按类型查找,单个 bean:" + user);
  46. }
  47. /**
  48. * 按类型查找:多个 bean
  49. *
  50. * @param beanFactory bean工厂
  51. */
  52. private static void lookupCollectionByType(BeanFactory beanFactory) {
  53. if (beanFactory instanceof ListableBeanFactory) {
  54. ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
  55. // key 为 bean 名称
  56. Map<String, UserForBasicInject> users = listableBeanFactory.getBeansOfType(UserForBasicInject.class);
  57. System.out.println("按类型查找,多个 bean:" + users);
  58. }
  59. }
  60. /**
  61. * 按注解查找
  62. *
  63. * @param beanFactory bean工厂
  64. */
  65. private static void lookupByAnnotationType(BeanFactory beanFactory) {
  66. if (beanFactory instanceof ListableBeanFactory) {
  67. ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
  68. // key 为 bean 名称
  69. Map<String, User> users = (Map) listableBeanFactory.getBeansWithAnnotation(Super.class);
  70. System.out.println("按注解查找:" + users);
  71. }
  72. }
  73. }

SuperUserForBasicInject.class

  1. /**
  2. * 超级用户--用于演示基础类型注入
  3. *
  4. * @author mindartisan.blog.csdn.net
  5. * @date
  6. */
  7. @Super
  8. public class SuperUserForBasicInject extends UserForBasicInject {
  9. private String address;
  10. public String getAddress() {
  11. return address;
  12. }
  13. public void setAddress(String address) {
  14. this.address = address;
  15. }
  16. @Override
  17. public String toString() {
  18. return "SuperUser{" +
  19. "address='" + address + '\'' +
  20. "} " + super.toString();
  21. }
  22. }

集合类型注入

数组类型(Array):原生类型、标量类型、常规类型、Spring 类型
集合类型(Collection):

  • Collection:List、Set(SortedSet、NavigableSet、EnumSet)
  • Map:Properties

相关代码:
City.class,复用基础类型注入
UserForCollectionInject.class

  1. /**
  2. * 用户--用于演示集合类型注入
  3. *
  4. * @author mindartisan.blog.csdn.net
  5. * @date
  6. */
  7. public class UserForCollectionInject {
  8. private Long id;
  9. private String name;
  10. private City city;
  11. private City[] workCities;
  12. private List<City> lifeCities;
  13. public City[] getWorkCities() {
  14. return workCities;
  15. }
  16. public void setWorkCities(City[] workCities) {
  17. this.workCities = workCities;
  18. }
  19. public List<City> getLifeCities() {
  20. return lifeCities;
  21. }
  22. public void setLifeCities(List<City> lifeCities) {
  23. this.lifeCities = lifeCities;
  24. }
  25. // City 和 Resource 相关用于演示基本类型注入
  26. public City getCity() {
  27. return city;
  28. }
  29. public void setCity(City city) {
  30. this.city = city;
  31. }
  32. private Resource configFileLocation;
  33. public Resource getConfigFileLocation() {
  34. return configFileLocation;
  35. }
  36. public void setConfigFileLocation(Resource configFileLocation) {
  37. this.configFileLocation = configFileLocation;
  38. }
  39. public Long getId() {
  40. return id;
  41. }
  42. public void setId(Long id) {
  43. this.id = id;
  44. }
  45. public String getName() {
  46. return name;
  47. }
  48. public void setName(String name) {
  49. this.name = name;
  50. }
  51. @Override
  52. public String toString() {
  53. return "UserForCollectionInject{" +
  54. "id=" + id +
  55. ", name='" + name + '\'' +
  56. ", city=" + city +
  57. ", workCities=" + Arrays.toString(workCities) +
  58. ", lifeCities=" + lifeCities +
  59. ", configFileLocation=" + configFileLocation +
  60. '}';
  61. }
  62. // @Override
  63. // public String toString() {
  64. // return "User{" +
  65. // "id=" + id +
  66. // ", name='" + name + '\'' +
  67. // '}';
  68. // }
  69. /**
  70. * 通过静态方法实例化
  71. *
  72. * @return {@link UserForCollectionInject}
  73. */
  74. public static UserForCollectionInject createUser(){
  75. UserForCollectionInject user = new UserForCollectionInject();
  76. user.setId(1L);
  77. user.setName("Steve");
  78. return user;
  79. }
  80. }

DependencyLookUpDemoForCollectionInject.class

  1. /**
  2. * 依赖查找示例--用于演示集合类型注入
  3. *
  4. * @author mindartisan.blog.csdn.net
  5. * @date
  6. */
  7. public class DependencyLookUpDemoForCollectionInject {
  8. public static void main(String[] args) {
  9. // 配置 XML 配置文件,两个方式均可
  10. // 启动 Spring 应用上下文
  11. BeanFactory beanFactory = new ClassPathXmlApplicationContext("META-INF/dependency-lookup-context-collection" +
  12. "-inject" +
  13. ".xml");
  14. // BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/dependency-lookup-context.xml");
  15. lookupInRealTime(beanFactory);
  16. lookupInLazy(beanFactory);
  17. lookupSingleByType(beanFactory);
  18. lookupCollectionByType(beanFactory);
  19. lookupByAnnotationType(beanFactory);
  20. }
  21. /**
  22. * 通过名称:实时查找
  23. *
  24. * @param beanFactory bean工厂
  25. */
  26. private static void lookupInRealTime(BeanFactory beanFactory) {
  27. UserForCollectionInject user = (UserForCollectionInject) beanFactory.getBean("userForCollectionInject");
  28. System.out.println("通过名称,实时查找:" + user);
  29. }
  30. /**
  31. * 通过名称:延迟查找
  32. *
  33. * @param beanFactory bean工厂
  34. */
  35. private static void lookupInLazy(BeanFactory beanFactory) {
  36. ObjectFactory<UserForCollectionInject> objectFactoryCreatingFactoryBean = (ObjectFactory<UserForCollectionInject>) beanFactory.getBean("objectFactoryCreatingFactoryBean");
  37. UserForCollectionInject user = objectFactoryCreatingFactoryBean.getObject();
  38. System.out.println("通过名称,延迟查找:" + user);
  39. }
  40. /**
  41. * 按类型查找:单个 bean
  42. *
  43. * @param beanFactory bean工厂
  44. */
  45. private static void lookupSingleByType(BeanFactory beanFactory) {
  46. UserForCollectionInject user = beanFactory.getBean(UserForCollectionInject.class);
  47. System.out.println("按类型查找,单个 bean:" + user);
  48. }
  49. /**
  50. * 按类型查找:多个 bean
  51. *
  52. * @param beanFactory bean工厂
  53. */
  54. private static void lookupCollectionByType(BeanFactory beanFactory) {
  55. if (beanFactory instanceof ListableBeanFactory) {
  56. ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
  57. // key 为 bean 名称
  58. Map<String, UserForCollectionInject> users = listableBeanFactory.getBeansOfType(UserForCollectionInject.class);
  59. System.out.println("按类型查找,多个 bean:" + users);
  60. }
  61. }
  62. /**
  63. * 按注解查找
  64. *
  65. * @param beanFactory bean工厂
  66. */
  67. private static void lookupByAnnotationType(BeanFactory beanFactory) {
  68. if (beanFactory instanceof ListableBeanFactory) {
  69. ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
  70. // key 为 bean 名称
  71. Map<String, User> users = (Map) listableBeanFactory.getBeansWithAnnotation(Super.class);
  72. System.out.println("按注解查找:" + users);
  73. }
  74. }
  75. }

dependency-lookup-context-collection-inject.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5. <bean id="userForCollectionInject" class="com.mindartisan.spring.geek.ioc.overview.domain.UserForCollectionInject"
  6. autowire="byName">
  7. <property name="id" value="1"/>
  8. <property name="name" value="Steve"/>
  9. <property name="city" value="BEIJING"/>
  10. <property name="workCities" value="BEIJING,SHANGHAI"/>
  11. <!--<property name="lifeCities" value="BEIJING,GUANGZHOU,SHANGHAI"/>-->
  12. <property name="lifeCities">
  13. <list>
  14. <value>BEIJING</value>
  15. <value>GUANGZHOU</value>
  16. <value>SHANGHAI</value>
  17. </list>
  18. </property>
  19. <property name="configFileLocation" value="classpath:/META-INF/user-config.properties"/>
  20. </bean>
  21. <bean id="superUserForCollectionInject"
  22. class="com.mindartisan.spring.geek.ioc.overview.domain.SuperUserForCollectionInject"
  23. parent="userForCollectionInject"
  24. primary="true">
  25. <property name="address" value="北京"/>
  26. </bean>
  27. <!--延迟查找使用-->
  28. <bean id="objectFactoryCreatingFactoryBean"
  29. class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
  30. <property name="targetBeanName" value="userForCollectionInject"/>
  31. </bean>
  32. </beans>

UserForCollectionInject.class

  1. /**
  2. * 用户--用于演示集合类型注入
  3. *
  4. * @author mindartisan.blog.csdn.net
  5. * @date
  6. */
  7. public class UserForCollectionInject {
  8. private Long id;
  9. private String name;
  10. private City city;
  11. private City[] workCities;
  12. private List<City> lifeCities;
  13. public City[] getWorkCities() {
  14. return workCities;
  15. }
  16. public void setWorkCities(City[] workCities) {
  17. this.workCities = workCities;
  18. }
  19. public List<City> getLifeCities() {
  20. return lifeCities;
  21. }
  22. public void setLifeCities(List<City> lifeCities) {
  23. this.lifeCities = lifeCities;
  24. }
  25. // City 和 Resource 相关用于演示基本类型注入
  26. public City getCity() {
  27. return city;
  28. }
  29. public void setCity(City city) {
  30. this.city = city;
  31. }
  32. private Resource configFileLocation;
  33. public Resource getConfigFileLocation() {
  34. return configFileLocation;
  35. }
  36. public void setConfigFileLocation(Resource configFileLocation) {
  37. this.configFileLocation = configFileLocation;
  38. }
  39. public Long getId() {
  40. return id;
  41. }
  42. public void setId(Long id) {
  43. this.id = id;
  44. }
  45. public String getName() {
  46. return name;
  47. }
  48. public void setName(String name) {
  49. this.name = name;
  50. }
  51. @Override
  52. public String toString() {
  53. return "UserForCollectionInject{" +
  54. "id=" + id +
  55. ", name='" + name + '\'' +
  56. ", city=" + city +
  57. ", workCities=" + Arrays.toString(workCities) +
  58. ", lifeCities=" + lifeCities +
  59. ", configFileLocation=" + configFileLocation +
  60. '}';
  61. }
  62. // @Override
  63. // public String toString() {
  64. // return "User{" +
  65. // "id=" + id +
  66. // ", name='" + name + '\'' +
  67. // '}';
  68. // }
  69. /**
  70. * 通过静态方法实例化
  71. *
  72. * @return {@link UserForCollectionInject}
  73. */
  74. public static UserForCollectionInject createUser(){
  75. UserForCollectionInject user = new UserForCollectionInject();
  76. user.setId(1L);
  77. user.setName("Steve");
  78. return user;
  79. }
  80. }

限定注入

使用注解 @Qualifier 限定

  • 通过 Bean 名称限定
  • 通过分组限定

相关代码:
QualifierAnnotationDependencyInjectDemo.class

  1. /**
  2. * Qualifier 注解依赖注入示例
  3. *
  4. * @author mindartisan.blog.csdn.net
  5. * @date
  6. */
  7. public class QualifierAnnotationDependencyInjectDemo {
  8. @Autowired // 会注入 superUser,因为 primary = true
  9. private User user;
  10. @Autowired
  11. @Qualifier("user") // 指定 bean 名称或者 id
  12. private User namedUser;
  13. @Bean
  14. @Qualifier // 逻辑分组
  15. public User user1() {
  16. return createUser(101L);
  17. }
  18. @Bean
  19. @Qualifier // 逻辑分组
  20. public User user2() {
  21. return createUser(102L);
  22. }
  23. // 上述定义了 4 个 User 类型的 Bean:superUser、user、user1、user2
  24. @Autowired
  25. private Collection<User> allUsers; // 两个 Bean:user+namedUser
  26. @Autowired
  27. @Qualifier // 逻辑分组
  28. private Collection<User> qualifierUsers; // 没用 @UserGroup 之前:2 个 bean 标注了 @Qualifier 注解的 user1 user2;用了之后 4
  29. // 个:user1、user2、user3、user4
  30. // 下述演示 @Qualifier 分组限定
  31. private static User createUser(Long id) {
  32. User user = new User();
  33. user.setId(id);
  34. return user;
  35. }
  36. @Bean
  37. @UserGroup
  38. public User user3() {
  39. return createUser(103L);
  40. }
  41. @Bean
  42. @UserGroup
  43. public User user4() {
  44. return createUser(104L);
  45. }
  46. @Bean
  47. @UserGroup
  48. public User user5() {
  49. return createUser(105L);
  50. }
  51. @Autowired
  52. @UserGroup
  53. private Collection<User> userGroup; // 3 个 Bean,user3、user4、user5
  54. public static void main(String[] args) {
  55. // 创建 BeanFactory 容器
  56. AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
  57. // 注册 配置类(配置类也是 Spring 的 Bean)
  58. applicationContext.register(QualifierAnnotationDependencyInjectDemo.class);
  59. // 将 User Bean 初始化,供 userHolder(User user) 使用
  60. XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
  61. String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
  62. // 加载 XML 资源,解析并生成 BeanDefinition
  63. xmlBeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
  64. // 启动 Spring 应用上下文
  65. applicationContext.refresh();
  66. // 依赖查找 AnnotationDependencyFieldInjectionDemo bean
  67. QualifierAnnotationDependencyInjectDemo demoBean = applicationContext.getBean(QualifierAnnotationDependencyInjectDemo.class);
  68. System.out.println("demoBean.user" + demoBean.user);
  69. System.out.println("demoBean.namedUser" + demoBean.namedUser);
  70. System.out.println("demoBean.allUsers" + demoBean.allUsers);
  71. System.out.println("demoBean.qualifierUsers" + demoBean.qualifierUsers);
  72. System.out.println("demoBean.userGroup" + demoBean.userGroup);
  73. // 关闭 Spring 应用上下文
  74. applicationContext.close();
  75. }
  76. }

UserGroup.class

  1. /**
  2. * 用户组 注解,扩展 @Qualifier
  3. *
  4. * @author mindartisan.blog.csdn.net
  5. * @date
  6. */
  7. @Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
  8. @Retention(RetentionPolicy.RUNTIME)
  9. @Inherited
  10. @Documented
  11. @Qualifier
  12. public @interface UserGroup {
  13. }

基于注解 @Qualifier 扩展限定

  • 自定义注解:如 Spring Cloud 的 @LoadBalanced

image.png
一个有 负载均衡 能力的 RestTemplate,一个没有 负载均衡 能力的 RestTemplate

延迟依赖注入

使用 API ObjectFactory 延迟注入

单一类型、集合类型

使用 API ObjectProvider 延迟注入(推荐)

单一类型、集合类型

相关代码:
LazyAnnotationDependencyInjectDemo.class

  1. /**
  2. * 使用 ObjectProvider 实现延迟注入
  3. *
  4. * @author mindartisan.blog.csdn.net
  5. * @date
  6. */
  7. public class LazyAnnotationDependencyInjectDemo {
  8. @Autowired
  9. private User user; // 实时注入
  10. @Autowired
  11. private ObjectProvider<User> userObjectProvider;
  12. @Autowired
  13. private ObjectFactory<Collection<User>> collectionObjectFactory;
  14. public static void main(String[] args) {
  15. // 创建 BeanFactory 容器
  16. AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
  17. // 注册 配置类(配置类也是 Spring 的 Bean)
  18. applicationContext.register(LazyAnnotationDependencyInjectDemo.class);
  19. // 将 User Bean 初始化,供 userHolder(User user) 使用
  20. XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
  21. String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
  22. // 加载 XML 资源,解析并生成 BeanDefinition
  23. xmlBeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
  24. // 启动 Spring 应用上下文
  25. applicationContext.refresh();
  26. // 依赖查找 AnnotationDependencyFieldInjectionDemo bean
  27. LazyAnnotationDependencyInjectDemo demoBean = applicationContext.getBean(LazyAnnotationDependencyInjectDemo.class);
  28. System.out.println("demoBean.user" + demoBean.user);
  29. System.out.println("demoBean.userObjectProvider" + demoBean.userObjectProvider.getObject());
  30. System.out.println("------");
  31. demoBean.userObjectProvider.forEach(System.out::println);
  32. System.out.println("-------");
  33. System.out.println("demoBean.collectionObjectFactory" + demoBean.collectionObjectFactory.getObject());
  34. demoBean.collectionObjectFactory.getObject().forEach(System.out::println);
  35. // 关闭 Spring 应用上下文
  36. applicationContext.close();
  37. }
  38. }

依赖处理过程

基础知识

入口:DefaultListableBeanFactory#resolveDependency
依赖描述符:DependencyDescriptor
自动绑定候选对象处理器:AutowireCandidateResolver

DependencyDescriptor

  1. public class DependencyDescriptor extends InjectionPoint implements Serializable {
  2. private final Class<?> declaringClass; // 当前要注入的容器(声明的类)
  3. @Nullable // 可以为空,Spring 注解
  4. private String methodName; // 方法名称
  5. @Nullable // 可以为空,Spring 注解
  6. private Class<?>[] parameterTypes; // 构造器参数或方法参数
  7. private int parameterIndex; // 参数的索引
  8. @Nullable // 可以为空,Spring 注解
  9. private String fieldName; // 属性名
  10. private final boolean required; //@Autowired 注解的 required 对应
  11. private final boolean eager; // 是否延迟:Lazy = true -> eager = false
  12. private int nestingLevel = 1;
  13. @Nullable
  14. private Class<?> containingClass; // 注入到哪个类里了
  15. @Nullable
  16. private transient volatile ResolvableType resolvableType; // Spring 的泛型输出
  17. @Nullable
  18. private transient volatile TypeDescriptor typeDescriptor;
  19. // 省略方法
  20. }

相关代码:
AnnotationDependencyInjectResolutionDemo.class

  1. /**
  2. * 注解驱动的依赖注入处理流程示例
  3. *
  4. * @author mindartisan.blog.csdn.net
  5. * @date
  6. */
  7. public class AnnotationDependencyInjectResolutionDemo {
  8. /**
  9. * 单一注入:
  10. * 依赖应找(处理)
  11. * DependencyDescriptor->
  12. * 必须(required = true)
  13. * 实时注入(eager=true)
  14. * 通过类型(User.class)
  15. * 字段名称(“user")
  16. * 是否首要(primary = true)
  17. */
  18. @Autowired
  19. private User user;
  20. public static void main(String[] args) {
  21. // 创建 BeanFactory 容器
  22. AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
  23. // 注册 配置类(配置类也是 Spring 的 Bean)
  24. applicationContext.register(AnnotationDependencyInjectResolutionDemo.class);
  25. // 将 User Bean 初始化,供 userHolder(User user) 使用
  26. XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
  27. String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
  28. // 加载 XML 资源,解析并生成 BeanDefinition
  29. xmlBeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
  30. // 启动 Spring 应用上下文
  31. applicationContext.refresh();
  32. // 依赖查找 AnnotationDependencyFieldInjectionDemo bean
  33. AnnotationDependencyInjectResolutionDemo demoBean = applicationContext.getBean(AnnotationDependencyInjectResolutionDemo.class);
  34. System.out.println("demoBean.user" + demoBean.user);
  35. // 关闭 Spring 应用上下文
  36. applicationContext.close();
  37. }
  38. }

debug 验证

断点位置:DefaultListableBeanFactory#resolveDependency() -> descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());

  1. @Override
  2. @Nullable
  3. public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
  4. @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
  5. // 断点在下一行
  6. descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
  7. if (Optional.class == descriptor.getDependencyType()) {
  8. return createOptionalDependency(descriptor, requestingBeanName);
  9. }
  10. else if (ObjectFactory.class == descriptor.getDependencyType() ||
  11. ObjectProvider.class == descriptor.getDependencyType()) {
  12. return new DependencyObjectProvider(descriptor, requestingBeanName);
  13. }
  14. else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
  15. return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
  16. }
  17. else {
  18. Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
  19. descriptor, requestingBeanName);
  20. if (result == null) {
  21. result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
  22. }
  23. return result;
  24. }
  25. }

image.png在当前示例下,前几个 if 都为 false,直接进入最后的 else,result 此时也会为 null,直接进入 doResolveDependency()查看。

断点位置:DefaultListableBeanFactory#doResolveDependency() -> InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);

  1. @Nullable
  2. public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
  3. @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
  4. // 断点在下一行
  5. InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
  6. try {
  7. Object shortcut = descriptor.resolveShortcut(this);
  8. if (shortcut != null) {
  9. return shortcut;
  10. }
  11. Class<?> type = descriptor.getDependencyType();
  12. Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
  13. if (value != null) {
  14. if (value instanceof String) {
  15. String strVal = resolveEmbeddedValue((String) value);
  16. BeanDefinition bd = (beanName != null && containsBean(beanName) ?
  17. getMergedBeanDefinition(beanName) : null);
  18. value = evaluateBeanDefinitionString(strVal, bd);
  19. }
  20. TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
  21. try {
  22. return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
  23. }
  24. catch (UnsupportedOperationException ex) {
  25. // A custom TypeConverter which does not support TypeDescriptor resolution...
  26. return (descriptor.getField() != null ?
  27. converter.convertIfNecessary(value, type, descriptor.getField()) :
  28. converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
  29. }
  30. }
  31. // 是否多个 Bean
  32. Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
  33. if (multipleBeans != null) {
  34. return multipleBeans;
  35. }
  36. // 此时会有两个 bean:user、superUser
  37. Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
  38. if (matchingBeans.isEmpty()) {
  39. if (isRequired(descriptor)) {
  40. raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
  41. }
  42. return null;
  43. }
  44. String autowiredBeanName;
  45. Object instanceCandidate;
  46. if (matchingBeans.size() > 1) {
  47. autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
  48. if (autowiredBeanName == null) {
  49. if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
  50. return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
  51. }
  52. else {
  53. // In case of an optional Collection/Map, silently ignore a non-unique case:
  54. // possibly it was meant to be an empty collection of multiple regular beans
  55. // (before 4.3 in particular when we didn't even look for collection beans).
  56. return null;
  57. }
  58. }
  59. instanceCandidate = matchingBeans.get(autowiredBeanName);
  60. }
  61. else {
  62. // We have exactly one match.
  63. Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
  64. autowiredBeanName = entry.getKey();
  65. instanceCandidate = entry.getValue();
  66. }
  67. if (autowiredBeanNames != null) {
  68. autowiredBeanNames.add(autowiredBeanName);
  69. }
  70. if (instanceCandidate instanceof Class) {
  71. instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
  72. }
  73. Object result = instanceCandidate;
  74. if (result instanceof NullBean) {
  75. if (isRequired(descriptor)) {
  76. raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
  77. }
  78. result = null;
  79. }
  80. if (!ClassUtils.isAssignableValue(type, result)) {
  81. throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
  82. }
  83. return result;
  84. }
  85. finally {
  86. ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
  87. }
  88. }

DefaultListableBeanFactory#findAutowireCandidates()

找符合类型的 bean,此例中是 user,会有两个 user 和 superUser

  1. protected Map<String, Object> findAutowireCandidates(
  2. @Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
  3. String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
  4. this, requiredType, true, descriptor.isEager());
  5. Map<String, Object> result = new LinkedHashMap<>(candidateNames.length);
  6. for (Map.Entry<Class<?>, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {
  7. Class<?> autowiringType = classObjectEntry.getKey();
  8. if (autowiringType.isAssignableFrom(requiredType)) {
  9. Object autowiringValue = classObjectEntry.getValue();
  10. autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
  11. if (requiredType.isInstance(autowiringValue)) {
  12. result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
  13. break;
  14. }
  15. }
  16. }
  17. for (String candidate : candidateNames) {
  18. if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
  19. addCandidateEntry(result, candidate, descriptor, requiredType);
  20. }
  21. }
  22. if (result.isEmpty()) {
  23. boolean multiple = indicatesMultipleBeans(requiredType);
  24. // Consider fallback matches if the first pass failed to find anything...
  25. DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
  26. for (String candidate : candidateNames) {
  27. if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor) &&
  28. (!multiple || getAutowireCandidateResolver().hasQualifier(descriptor))) {
  29. addCandidateEntry(result, candidate, descriptor, requiredType);
  30. }
  31. }
  32. if (result.isEmpty() && !multiple) {
  33. // Consider self references as a final pass...
  34. // but in the case of a dependency collection, not the very same bean itself.
  35. for (String candidate : candidateNames) {
  36. if (isSelfReference(beanName, candidate) &&
  37. (!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&
  38. isAutowireCandidate(candidate, fallbackDescriptor)) {
  39. addCandidateEntry(result, candidate, descriptor, requiredType);
  40. }
  41. }
  42. }
  43. }
  44. return result;
  45. }

DefaultListableBeanFactory#determinePrimaryCandidate()

主要是找 primary bean

  1. protected String determinePrimaryCandidate(Map<String, Object> candidates, Class<?> requiredType) {
  2. String primaryBeanName = null;
  3. for (Map.Entry<String, Object> entry : candidates.entrySet()) {
  4. String candidateBeanName = entry.getKey();
  5. Object beanInstance = entry.getValue();
  6. if (isPrimary(candidateBeanName, beanInstance)) {
  7. if (primaryBeanName != null) {
  8. boolean candidateLocal = containsBeanDefinition(candidateBeanName);
  9. boolean primaryLocal = containsBeanDefinition(primaryBeanName);
  10. if (candidateLocal && primaryLocal) {
  11. throw new NoUniqueBeanDefinitionException(requiredType, candidates.size(),
  12. "more than one 'primary' bean found among candidates: " + candidates.keySet());
  13. }
  14. else if (candidateLocal) {
  15. primaryBeanName = candidateBeanName;
  16. }
  17. }
  18. else {
  19. primaryBeanName = candidateBeanName;
  20. }
  21. }
  22. }
  23. return primaryBeanName;
  24. }

DefaultListableBeanFactory#isPrimary()

在这里利用 BeanDefinition 里的 isPrimary 判断

  1. protected boolean isPrimary(String beanName, Object beanInstance) {
  2. String transformedBeanName = transformedBeanName(beanName);
  3. if (containsBeanDefinition(transformedBeanName)) {
  4. return getMergedLocalBeanDefinition(transformedBeanName).isPrimary();
  5. }
  6. BeanFactory parent = getParentBeanFactory();
  7. return (parent instanceof DefaultListableBeanFactory &&
  8. ((DefaultListableBeanFactory) parent).isPrimary(transformedBeanName, beanInstance));
  9. }

如果在 AnnotationDependencyInjectResolutionDemo.class 添加:

  1. /*
  2. * 集合注入
  3. *
  4. */
  5. @Autowired
  6. private Map<String, User> users;

则可以在 DefaultListableBeanFactory#resolveMultipleBeans() 方法打断点查看,不再赘述。

  1. else if (Map.class == type) {
  2. ResolvableType mapType = descriptor.getResolvableType().asMap();
  3. Class<?> keyType = mapType.resolveGeneric(0);
  4. // 省略代码
  5. }

如果在 AnnotationDependencyInjectResolutionDemo.class 添加:

  1. @Autowired
  2. private Optional<User> optionalUser;

则可以在 DefaultListableBeanFactory#createOptionalDependency() 方法打断点查看,不再赘述。

  1. if (Optional.class == descriptor.getDependencyType()) {
  2. return createOptionalDependency(descriptor, requestingBeanName);
  3. }

@Autowired 注入原理

大概流程:

  1. 元信息解析 -> 和 DependencyDescriptor 相关
  2. 依赖查找 -> 可以理解为依赖处理的过程
  3. 依赖注入(注入到方法、字段)

    源码解析

    以「依赖处理流程」中的代码为例,断点在 DefaultListableBeanFactory#resolveDependency() -> descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());

使用 IDEA 的 debug 工具,查看调用栈相关信息:
image.png
进入方法:

  1. @Override
  2. protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
  3. Field field = (Field) this.member;
  4. Object value;
  5. if (this.cached) {
  6. value = resolvedCachedArgument(beanName, this.cachedFieldValue);
  7. }
  8. else {
  9. DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
  10. desc.setContainingClass(bean.getClass());
  11. Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
  12. Assert.state(beanFactory != null, "No BeanFactory available");
  13. TypeConverter typeConverter = beanFactory.getTypeConverter();
  14. try {
  15. // 此处进行依赖处理的流程
  16. value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
  17. }
  18. catch (BeansException ex) {
  19. throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
  20. }
  21. synchronized (this) {
  22. if (!this.cached) {
  23. if (value != null || this.required) {
  24. this.cachedFieldValue = desc;
  25. registerDependentBeans(beanName, autowiredBeanNames);
  26. if (autowiredBeanNames.size() == 1) {
  27. String autowiredBeanName = autowiredBeanNames.iterator().next();
  28. if (beanFactory.containsBean(autowiredBeanName) &&
  29. beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
  30. this.cachedFieldValue = new ShortcutDependencyDescriptor(
  31. desc, autowiredBeanName, field.getType());
  32. }
  33. }
  34. }
  35. else {
  36. this.cachedFieldValue = null;
  37. }
  38. this.cached = true;
  39. }
  40. }
  41. }
  42. if (value != null) {
  43. // 通过反射的形式对 field 赋值
  44. ReflectionUtils.makeAccessible(field);
  45. field.set(bean, value);
  46. }
  47. }

一些细节:

主要引用了 极客时间 Spring IoC 课程 中的一些精选评论。

引用一:

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

        引用二:

        image.png

        引用三:

        image.png

        JSR-330 @Inject 注入原理

        如果 JSR-330 存在与 ClassPath 中,复用 AutowiredAnnotationBeanPostProcessor实现 ```java private final Set> autowiredAnnotationTypes = new LinkedHashSet<>(4);

/**

  1. * Create a new {@code AutowiredAnnotationBeanPostProcessor} for Spring's
  2. * standard {@link Autowired @Autowired} and {@link Value @Value} annotations.
  3. * <p>Also supports JSR-330's {@link javax.inject.Inject @Inject} annotation,
  4. * if available.
  5. */
  6. @SuppressWarnings("unchecked")
  7. public AutowiredAnnotationBeanPostProcessor() {
  8. this.autowiredAnnotationTypes.add(Autowired.class);
  9. this.autowiredAnnotationTypes.add(Value.class);
  10. try {
  11. this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
  12. ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
  13. logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
  14. }
  15. catch (ClassNotFoundException ex) {
  16. // JSR-330 API not available - simply skip.
  17. }
  18. }
  1. 在使用时,优先使用 `@Autowired`,参见:
  2. ```java
  3. @Nullable
  4. private MergedAnnotation<?> findAutowiredAnnotation(AccessibleObject ao) {
  5. MergedAnnotations annotations = MergedAnnotations.from(ao);
  6. for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
  7. MergedAnnotation<?> annotation = annotations.get(type);
  8. if (annotation.isPresent()) {
  9. return annotation;
  10. }
  11. }
  12. return null;
  13. }

Java 通用注解注入原理

基础知识

基于 CommonAnnotationBeanPostProcessor实现:

  1. 注入注解
    1. javax.xml.ws.WebServiceRef
    2. javax.ejb.EJB
    3. javax.annotation.Resource
  2. 生命周期注解
    1. javax.annotation.PostConstruct
    2. javax.annotation.PreDestroy

      源码解析

      先来个之前说到的 AutowiredAnnotationBeanPostProcessor 做个对比:
      image.png
      会发现,CommonAnotationBeanPostProcessor 比 AutowiredAnnotationBeanPostProcessor 多实现了 InitDestroyAnnotatioBeanPostProcessor。

再详细对比下此方法 postProcessMergedBeanDefinition:

  1. // CommonAnnotationBeanPostProcessor#postProcessMergedBeanDefinition()
  2. @Override
  3. public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
  4. super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
  5. InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
  6. metadata.checkConfigMembers(beanDefinition);
  7. }
  8. // AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition()
  9. @Override
  10. public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
  11. InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
  12. metadata.checkConfigMembers(beanDefinition);
  13. }

再去 super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName) 里看下:

  1. // InitDestroyAnnotationBeanPostProcessor#postProcessMergedBeanDefinition(beanDefinition, beanType, beanName)
  2. @Override
  3. public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
  4. LifecycleMetadata metadata = findLifecycleMetadata(beanType);
  5. metadata.checkConfigMembers(beanDefinition);
  6. }

可以看到,CommonAnotationBeanPostProcessor 比 AutowiredAnnotationBeanPostProcessor 的处理流程其实差不多,当前可以看到多的有LifecycleMetadata 的处理:

  1. /**
  2. * Class representing information about annotated init and destroy methods.
  3. */
  4. private class LifecycleMetadata {
  5. private final Class<?> targetClass;
  6. private final Collection<LifecycleElement> initMethods;
  7. private final Collection<LifecycleElement> destroyMethods;
  8. @Nullable
  9. private volatile Set<LifecycleElement> checkedInitMethods;
  10. @Nullable
  11. private volatile Set<LifecycleElement> checkedDestroyMethods;
  12. public LifecycleMetadata(Class<?> targetClass, Collection<LifecycleElement> initMethods,
  13. Collection<LifecycleElement> destroyMethods) {
  14. this.targetClass = targetClass;
  15. this.initMethods = initMethods;
  16. this.destroyMethods = destroyMethods;
  17. }
  18. }

注入源码解析

回到 Java 通用注解注入原理的问题中来,调用链:

  1. CommonAnotationBeanPostProcessor#postProcessProperties();
  2. CommonAnotationBeanPostProcessor#findResourceMetadata();
  3. CommonAnotationBeanPostProcessor#buildResourceMetadata();

CommonAnotationBeanPostProcessor#buildResourceMetadata() 相关代码:

  1. do {
  2. final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
  3. ReflectionUtils.doWithLocalFields(targetClass, field -> {
  4. if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) {
  5. if (Modifier.isStatic(field.getModifiers())) {
  6. throw new IllegalStateException("@WebServiceRef annotation is not supported on static fields");
  7. }
  8. currElements.add(new WebServiceRefElement(field, field, null));
  9. }
  10. else if (ejbRefClass != null && field.isAnnotationPresent(ejbRefClass)) {
  11. if (Modifier.isStatic(field.getModifiers())) {
  12. throw new IllegalStateException("@EJB annotation is not supported on static fields");
  13. }
  14. currElements.add(new EjbRefElement(field, field, null));
  15. }
  16. else if (field.isAnnotationPresent(Resource.class)) {
  17. if (Modifier.isStatic(field.getModifiers())) {
  18. throw new IllegalStateException("@Resource annotation is not supported on static fields");
  19. }
  20. if (!this.ignoredResourceTypes.contains(field.getType().getName())) {
  21. currElements.add(new ResourceElement(field, field, null));
  22. }
  23. }
  24. });

回调源码解析

构造器:

  1. /**
  2. * Create a new CommonAnnotationBeanPostProcessor,
  3. * with the init and destroy annotation types set to
  4. * {@link javax.annotation.PostConstruct} and {@link javax.annotation.PreDestroy},
  5. * respectively.
  6. */
  7. public CommonAnnotationBeanPostProcessor() {
  8. setOrder(Ordered.LOWEST_PRECEDENCE - 3);
  9. // 下面两行
  10. setInitAnnotationType(PostConstruct.class);
  11. setDestroyAnnotationType(PreDestroy.class);
  12. // 上面两行
  13. ignoreResourceType("javax.xml.ws.WebServiceContext");
  14. }
  1. public void setInitAnnotationType(Class<? extends Annotation> initAnnotationType) {
  2. this.initAnnotationType = initAnnotationType;
  3. }
  4. public void setDestroyAnnotationType(Class<? extends Annotation> destroyAnnotationType) {
  5. this.destroyAnnotationType = destroyAnnotationType;
  6. }

查找 initAnnotationType 的 usage,发现是 CommonAnotationBeanPostProcessor#buildResourceMetadata(),相关代码:

  1. private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
  2. if (!AnnotationUtils.isCandidateClass(clazz, Arrays.asList(this.initAnnotationType, this.destroyAnnotationType))) {
  3. return this.emptyLifecycleMetadata;
  4. }
  5. List<LifecycleElement> initMethods = new ArrayList<>();
  6. List<LifecycleElement> destroyMethods = new ArrayList<>();
  7. Class<?> targetClass = clazz;
  8. do {
  9. final List<LifecycleElement> currInitMethods = new ArrayList<>();
  10. final List<LifecycleElement> currDestroyMethods = new ArrayList<>();
  11. // 重点看此处代码:下述代码会处理被「@PostConstruct 以及 @PreDestroy」的方法
  12. ReflectionUtils.doWithLocalMethods(targetClass, method -> {
  13. if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
  14. LifecycleElement element = new LifecycleElement(method);
  15. currInitMethods.add(element);
  16. if (logger.isTraceEnabled()) {
  17. logger.trace("Found init method on class [" + clazz.getName() + "]: " + method);
  18. }
  19. }
  20. if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
  21. currDestroyMethods.add(new LifecycleElement(method));
  22. if (logger.isTraceEnabled()) {
  23. logger.trace("Found destroy method on class [" + clazz.getName() + "]: " + method);
  24. }
  25. }
  26. });
  27. initMethods.addAll(0, currInitMethods);
  28. destroyMethods.addAll(currDestroyMethods);
  29. targetClass = targetClass.getSuperclass();
  30. }
  31. while (targetClass != null && targetClass != Object.class);
  32. return (initMethods.isEmpty() && destroyMethods.isEmpty() ? this.emptyLifecycleMetadata :
  33. new LifecycleMetadata(clazz, initMethods, destroyMethods));
  34. }

再来看下 LifecycleElement:

  1. private static class LifecycleElement {
  2. private final Method method;
  3. private final String identifier;
  4. public LifecycleElement(Method method) {
  5. if (method.getParameterCount() != 0) {
  6. throw new IllegalStateException("Lifecycle method annotation requires a no-arg method: " + method);
  7. }
  8. this.method = method;
  9. this.identifier = (Modifier.isPrivate(method.getModifiers()) ?
  10. ClassUtils.getQualifiedMethodName(method) : method.getName());
  11. }
  12. public void invoke(Object target) throws Throwable {
  13. ReflectionUtils.makeAccessible(this.method);
  14. this.method.invoke(target, (Object[]) null);
  15. }
  16. // 省略部分代码
  17. }

查找 invoke 方法的 usages,会发现是 InitDestroyAnnotationBeanPostProcessor#invokeInitMethods() 以及 InitDestroyAnnotationBeanPostProcessor#invokeDestroyMethods()。

再查找上述两个方法的 usage,会发现分别是 postProcessBeforeInitialization()以及 postProcessBeforeDestruction()方法。

CommonAnotationBeanPostProcessor 与 AutowiredAnnotationBeanPostProcessor 顺序

二者都实现了 Ordered接口:

  1. CommonAnotationBeanPostProcessor 的 order 为 private int order = Ordered.LOWEST_PRECEDENCE - 3;,倒数第四位
  2. AutowiredAnnotationBeanPostProcessor 的 order 为 private int order = Ordered.LOWEST_PRECEDENCE - 2;,倒数第三位

所以:CommonAnotationBeanPostProcessor 会在 AutowiredAnnotationBeanPostProcessor 使用

自定义依赖注入注解

基于 AutowiredAnnotationBeanPostProcessor 实现

自定义个注解:MyAutowired.class

  1. /**
  2. * 自定义注解,利用了 @Autowired
  3. *
  4. * @author mindartisan.blog.csdn.net
  5. * @date
  6. */
  7. @Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
  8. @Retention(RetentionPolicy.RUNTIME)
  9. @Documented
  10. @Autowired
  11. public @interface MyAutowired {
  12. /**
  13. * Declares whether the annotated dependency is required.
  14. * <p>Defaults to {@code true}.
  15. */
  16. boolean required() default true;
  17. }

InjectedUser.class

  1. /**
  2. * 自定义依赖注入注解
  3. *
  4. * @author mindartisan.blog.csdn.net
  5. * @date
  6. */
  7. @Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
  8. @Retention(RetentionPolicy.RUNTIME)
  9. @Documented
  10. public @interface InjectedUser {
  11. }

主程序:MyAnnotationDependencyInjectResolutionDemo.class

  1. /**
  2. * 注解驱动的依赖注入处理流程示例
  3. *
  4. * @author mindartisan.blog.csdn.net
  5. * @date
  6. */
  7. public class MyAnnotationDependencyInjectResolutionDemo {
  8. /**
  9. * 单一注入:
  10. * 依赖应找(处理)
  11. * DependencyDescriptor->
  12. * 必须(required = true)
  13. * 实时注入(eager=true)
  14. * 通过类型(User.class)
  15. * 字段名称(“user")
  16. * 是否首要(primary = true)
  17. */
  18. @Autowired
  19. private User user;
  20. @MyAutowired
  21. private User myAutowiredUser;
  22. @Inject
  23. private User injectUser;
  24. @InjectedUser
  25. private User myInjectUser;
  26. // @Bean(name = AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)
  27. // public static AutowiredAnnotationBeanPostProcessor beanPostProcessor() {
  28. // AutowiredAnnotationBeanPostProcessor autowiredAnnotationBeanPostProcessor =
  29. // new AutowiredAnnotationBeanPostProcessor();
  30. // // 新的自定义注解+自带的实现
  31. // // 存在的问题,Inject 或者其他需要的注解不存在
  32. // Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(asList(Autowired.class,
  33. // Inject.class, InjectedUser.class));
  34. // autowiredAnnotationBeanPostProcessor.setAutowiredAnnotationTypes(autowiredAnnotationTypes);
  35. // return autowiredAnnotationBeanPostProcessor;
  36. // }
  37. @Bean
  38. @Order(Ordered.LOWEST_PRECEDENCE - 3)
  39. public static AutowiredAnnotationBeanPostProcessor beanPostProcessor() {
  40. AutowiredAnnotationBeanPostProcessor autowiredAnnotationBeanPostProcessor =
  41. new AutowiredAnnotationBeanPostProcessor();
  42. autowiredAnnotationBeanPostProcessor.setAutowiredAnnotationType(InjectedUser.class);
  43. return autowiredAnnotationBeanPostProcessor;
  44. }
  45. public static void main(String[] args) {
  46. // 创建 BeanFactory 容器
  47. AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
  48. // 注册 配置类(配置类也是 Spring 的 Bean)
  49. applicationContext.register(MyAnnotationDependencyInjectResolutionDemo.class);
  50. // 将 User Bean 初始化,供 userHolder(User user) 使用
  51. XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
  52. String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
  53. // 加载 XML 资源,解析并生成 BeanDefinition
  54. xmlBeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
  55. // 启动 Spring 应用上下文
  56. applicationContext.refresh();
  57. // 依赖查找 AnnotationDependencyFieldInjectionDemo bean
  58. MyAnnotationDependencyInjectResolutionDemo demoBean = applicationContext.getBean(MyAnnotationDependencyInjectResolutionDemo.class);
  59. System.out.println("demoBean.user" + "=" + demoBean.user);
  60. System.out.println("demoBean.injectUser" + "=" + demoBean.injectUser);
  61. System.out.println("demoBean.myAutowiredUser" + "=" + demoBean.myAutowiredUser);
  62. System.out.println("demoBean.myInjectUser" + "=" + demoBean.myInjectUser);
  63. // 关闭 Spring 应用上下文
  64. applicationContext.close();
  65. }
  66. }

主要是因为下面的代码(选下面的)

  1. @Bean(name = AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)
  2. public static AutowiredAnnotationBeanPostProcessor beanPostProcessor() {
  3. AutowiredAnnotationBeanPostProcessor autowiredAnnotationBeanPostProcessor =
  4. new AutowiredAnnotationBeanPostProcessor();
  5. // 新的自定义注解+自带的实现
  6. // 存在的问题:Inject 或者其他需要的注解不存在
  7. Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(asList(Autowired.class,
  8. Inject.class, InjectedUser.class));
  9. autowiredAnnotationBeanPostProcessor.setAutowiredAnnotationTypes(autowiredAnnotationTypes);
  10. return autowiredAnnotationBeanPostProcessor;
  11. }
  12. @Bean
  13. @Order(Ordered.LOWEST_PRECEDENCE - 3)
  14. public static AutowiredAnnotationBeanPostProcessor beanPostProcessor() {
  15. AutowiredAnnotationBeanPostProcessor autowiredAnnotationBeanPostProcessor =
  16. new AutowiredAnnotationBeanPostProcessor();
  17. autowiredAnnotationBeanPostProcessor.setAutowiredAnnotationType(InjectedUser.class);
  18. return autowiredAnnotationBeanPostProcessor;
  19. }

这里的方法上标注了 static 的原因:
image.png

自定义实现

这里没有讲

生命周期处理:

  1. InstantiationAwareBeanPostProcessor
  2. MergedBeanDefinitionPostProcessor

元数据:

  1. InjectedElement
  2. InjectionMetadata