Spring IoC 注入

依赖注入的模式和类型

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

  • XML 资源配置元信息
  • Java 注解配置元信息
  • API 配置元信息

• 自动模式 - 实现方提供依赖自动关联的方式,按照內建的注入规则

  • Autowiring(自动绑定)

依赖注入类型

依赖注入类型配置元数据举例
Setter 方法<proeprty name=“user” ref=“userBean”/>
构造器<constructor-arg name=“user” ref=“userBean” />
字段@Autowired User user;
方法@Autowired public void user(User user) { … }
接口回调class MyBean implements BeanFactoryAware { … }

自动绑定(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.

优点
• Autowiring can significantly reduce the need to specify properties or constructor arguments.
• Autowiring can update a configuration as your objects evolve.

自动绑定(Autowiring)模式

Autowiring modes

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

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

官方说明
Limitations and Disadvantages of Autowiring 小节
链接:https://docs.spring.io/spring/docs/5.2.2.RELEASE/spring-framework-reference/core.html#beans-autowired-exceptions

Setter 方法注入

实现方法
• 手动模式

  • XML 资源配置元信息
  • Java 注解配置元信息
  • API 配置元信息

• 自动模式

  • byName
  • byType
/**
 * 基于 API 实现依赖 Setter 方法注入示例
 */
public class ApiDependencySetterInjectionDemo {

    public static void main(String[] args) {

        // 创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();

        // 生成 UserHolder 的 BeanDefinition
        BeanDefinition userHolderBeanDefinition = createUserHolderBeanDefinition();
        // 注册 UserHolder 的 BeanDefinition
        applicationContext.registerBeanDefinition("userHolder", userHolderBeanDefinition);

        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);

        String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
        // 加载 XML 资源,解析并且生成 BeanDefinition
        beanDefinitionReader.loadBeanDefinitions(xmlResourcePath);

        // 启动 Spring 应用上下文
        applicationContext.refresh();

        // 依赖查找并且创建 Bean
        UserHolder userHolder = applicationContext.getBean(UserHolder.class);
        System.out.println(userHolder);

        // 显示地关闭 Spring 应用上下文
        applicationContext.close();
    }

    /**
     * 为 {@link UserHolder} 生成 {@link BeanDefinition}
     */
    private static BeanDefinition createUserHolderBeanDefinition() {
        BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserHolder.class);
        definitionBuilder.addPropertyReference("user", "superUser");
        return definitionBuilder.getBeanDefinition();
    }
}

构造器注入

实现方法
• 手动模式

  • XML 资源配置元信息
  • Java 注解配置元信息
  • API 配置元信息

• 自动模式

  • constructor
/**
 * 基于 API 实现依赖 Constructor 注入示例
 */
private static BeanDefinition createUserHolderBeanDefinition() {
    BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserHolder.class);
    definitionBuilder.addConstructorArgReference("superUser");
    return definitionBuilder.getBeanDefinition();
}

字段注入

实现方法
• 手动模式

  • Java 注解配置元信息
    • @Autowired
    • @Resource
    • @Inject(可选)
// @Autowired 会忽略掉static静态字段
@Autowired
private UserHolder userHolder;

@Resource
private UserHolder userHolder2;

方法注入

• 手动模式

  • Java 注解配置元信息
    • @Autowired
    • @Resource
    • @Inject(可选)
    • @Bean
@Autowired
public void init1(UserHolder userHolder) {
    this.userHolder = userHolder;
}

@Bean
public UserHolder userHolder(User user) {
    return new UserHolder(user);
}

接口回调注入

Aware 系列接口回调
• 自动模式

內建接口说明
BeanFactoryAware获取 IoC 容器 - BeanFactory
ApplicationContextAware获取 Spring 应用上下文 - ApplicationContext 对象
EnvironmentAware获取 Environment 对象
ResourceLoaderAware获取资源加载器 对象 - ResourceLoader
BeanClassLoaderAware获取加载当前 Bean Class 的 ClassLoader
BeanNameAware获取当前 Bean 的名称
MessageSourceAware获取 MessageSource 对象,用于 Spring 国际化
ApplicationEventPublisherAware获取 ApplicationEventPublishAware 对象,用于 Spring 事件
EmbeddedValueResolverAware获取 StringValueResolver 对象,用于占位符处理
public class AwareInterfaceDependencyInjectionDemo implements BeanFactoryAware, ApplicationContextAware {

    private static BeanFactory beanFactory;

    private static ApplicationContext applicationContext;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        AwareInterfaceDependencyInjectionDemo.beanFactory = beanFactory;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        AwareInterfaceDependencyInjectionDemo.applicationContext = applicationContext;
    }
}

依赖注入类型选择

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

基础类型注入

基础类型

• 原生类型(Primitive):boolean、byte、char、short、int、float、long、double
• 标量类型(Scalar):Number、Character、Boolean、Enum、Locale、Charset、Currency、Properties、UUID
• 常规类型(General):Object、String、TimeZone、Calendar、Optional 等
• Spring 类型:Resource、InputSource、Formatter 等

集合类型注入

集合类型

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

• 集合类型(Collection)

  • Collection:List、Set(SortedSet、NavigableSet、EnumSet)
  • Map:Properties
<bean id="user" class="org.geekbang.thinking.in.spring.ioc.overview.domain.User">
     <property name="id" value="1"/>
     <property name="name" value="小马哥"/>
     <property name="city" value="HANGZHOU"/>
     <property name="workCities" value="BEIJING,HANGZHOU"/>
     <property name="lifeCities">
         <list>
             <value>BEIJING</value>
             <value>SHANGHAI</value>
         </list>
     </property>
     <property name="configFileLocation" value="classpath:/META-INF/user-config.properties"/>
 </bean>

限定注入

• 使用注解 @Qualifier 限定

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

• 基于注解 @Qualifier 扩展限定

  • 自定义注解 - 如 Spring Cloud @LoadBalanced
 @Autowired
 private User user; // superUser -> primary =true

 @Autowired
 @Qualifier("user") // 指定 Bean 名称或 ID
 private User namedUser;

 // 整体应用上下文存在 4 个 User 类型的 Bean:
 // superUser
 // user
 // user1 -> @Qualifier
 // user2 -> @Qualifier

 @Autowired
 private Collection<User> allUsers; // 2 Beans = user + superUser

 @Autowired
 @Qualifier
 private Collection<User> qualifiedUsers; // 2 Beans = user1 + user2 -> 4 Beans = user1 + user2 + user3 + user4

 @Autowired
 @UserGroup
 private Collection<User> groupedUsers; // 2 Beans = user3 + user4

 @Bean
 @Qualifier // 进行逻辑分组
 public User user1() {
     return createUser(7L);
 }

 @Bean
 @Qualifier // 进行逻辑分组
 public static User user2() {
     return createUser(8L);

 }

 @Bean
 @UserGroup
 public static User user3() {
     return createUser(9L);
 }

 @Bean
 @UserGroup
 public static User user4() {
     return createUser(10L);
 }

延迟依赖注入

• 使用 API ObjectFactory 延迟注入

  • 单一类型
  • 集合类型

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

  • 单一类型
  • 集合类型
@Autowired
@Qualifier("user")
private User user; // 实时注入

@Autowired
private ObjectProvider<User> userObjectProvider; // 延迟注入

@Autowired
private ObjectFactory<Set<User>> usersObjectFactory;

@Autowired
@Lazy
@Qualifier("user")
private User user; 

依赖处理过程

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

@Autowired 注入

@Autowired 注入规则

• 非静态字段
• 非静态方法
• 构造器

@Autowired 注入过程

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

@Inject 注入

@Inject 注入过程

• 如果 JSR-330 存在于 ClassPath 中,复用 AutowiredAnnotationBeanPostProcessor 实现

Java通用注解注入原理

CommonAnnotationBeanPostProcessor

• 注入注解

  • javax.xml.ws.WebServiceRef
  • javax.ejb.EJB
  • javax.annotation.Resource

• 生命周期注解

  • javax.annotation.PostConstruct
  • javax.annotation.PreDestroy

自定义依赖注入注解

• 基于 AutowiredAnnotationBeanPostProcessor 实现

• 自定义实现

  • 生命周期处理
    • InstantiationAwareBeanPostProcessor
    • MergedBeanDefinitionPostProcessor

  • 元数据
    • InjectedElement
    • InjectionMetadata

@Bean
@Order(Ordered.LOWEST_PRECEDENCE - 3)
@Scope
public static AutowiredAnnotationBeanPostProcessor beanPostProcessor() {
    AutowiredAnnotationBeanPostProcessor beanPostProcessor = new AutowiredAnnotationBeanPostProcessor();
    beanPostProcessor.setAutowiredAnnotationType(InjectedUser.class);
    return beanPostProcessor;
}

面试题

有多少种依赖注入的方式?
答:构造器注入、Setter 注入、字段注入、方法注入、接口回调注入

你偏好构造器注入还是 Setter 注入?
答:两种依赖注入的方式均可使用,如果是必须依赖的话,那么推荐使用构造器注入,Setter 注入用于可选依赖。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值