栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

6. 依赖注入

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

6. 依赖注入

两层意思:

  • 注入 Spring Bean 或者可依赖对象(@Autowired)

  • 注入外部化配置(@Value)

6.1 依赖注入的模式
  • 手动模式

    • XML 资源配置元信息

    • Java 注解配置元信息

    • API 配置元信息(普通用户使用较少,框架开发者使用较多,需掌握)

  • 自动模式(官方不推荐使用自动绑定模式)

    • Autowiring(自动绑定)

依赖注入类型:

依赖注入类型配置元数据举例
Setter 方法
构造器
字段@Autowired User user;
方法@Autowired public void user(User user) {...}
接口回调class MyBean implements BeanFactoryAware {...}
6.2 自动绑定

6.2.1 自动绑定原因

Spring 容器能够根据自动绑定在合作的 Bean(依赖 Bean 和被依赖 Bean) 之间,通过某种策略自动处理这些合作者之间的关系

自动绑定优点:

  • 减少属性或者构造器参数的设置

  • 自动绑定能够更新配置

6.2.2 自动绑定模式

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

参考枚举类:org.springframework.beans.factory.annotation.Autowire

public enum Autowire {
​
    
    NO(AutowireCapableBeanFactory.AUTOWIRE_NO),
​
    
    BY_NAME(AutowireCapableBeanFactory.AUTOWIRE_BY_NAME),
​
    
    BY_TYPE(AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE);
​
​
    private final int value;
​
​
    Autowire(int value) {
        this.value = value;
    }
​
    public int value() {
        return this.value;
    }
​
    
    public boolean isAutowire() {
        return (this == BY_NAME || this == BY_TYPE);
    }
​
}

6.2.3 自动绑定限制以及不足(XML 特有)

  • 自动绑定会被属性或者构造器参数等注入覆盖

  • 无法绑定 String、原生类型、Class 类型以及这些类型的数组类型

  • 缺乏精确性

  • 自动绑定的信息很难在一些工具类中进行呈现,比如自动生成的文档等

  • 当绑定对象不止一个会有歧义,并且会报错

6.3 Setter 方法依赖注入
  • 手动模式

    • XML 资源配置元信息

    • Java 注解配置元信息

    • API 配置元信息

  • 自动模式

    • byName

    • byType

6.3.1 XML 方式

public class XmlDependencySetterInjectionDemo {
    public static void main(String[] args) {
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
        reader.loadBeanDefinitions("classpath:dependency-setter-injection.xml");
        System.out.println(factory.getBean(UserHolder.class));
    }
}


​
    
​
    
        
    

6.3.2 Java 注解

public class AnnotationDependencySetterInjectionDemo {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(AnnotationDependencySetterInjectionDemo.class);
​
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context);
        reader.loadBeanDefinitions("classpath:beans-ioc-lookup.xml");
​
        context.refresh();
​
        System.out.println(context.getBean(UserHolder.class));
​
        context.close();
    }
​
    @Bean
    public UserHolder userHolder(User user) {
        // 构造器方式
        // return new UserHolder(user);
​
        // setter 方式
        UserHolder holder = new UserHolder();
        holder.setUser(user);
        return holder;
    }
}

6.3.3 API 方式

public class ApiDependencySetterInjectionDemo {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        // 注册 BeanDefinition
        context.registerBeanDefinition("userHolder", createBeanDefinitionUserHolder());
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context);
        reader.loadBeanDefinitions("classpath:beans-ioc-lookup.xml");
​
        context.refresh();
​
        System.out.println(context.getBean(UserHolder.class));
​
        context.close();
    }
​
    private static BeanDefinition createBeanDefinitionUserHolder() {
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(UserHolder.class);
​
        builder.addPropertyReference("user", "superUser");
​
        return builder.getBeanDefinition();
    }
}

6.3.4 自动注入方式

public class AutowiringByNameDependencySetterInjectionDemo {
    public static void main(String[] args) {
        DefaultListableBeanFactory context = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context);
        reader.loadBeanDefinitions("autowiring-dependency-setter-injection.xml");
        System.out.println(context.getBean(UserHolder.class));
    }
}


​
    
​
    
    
    
    
6.4 构造器依赖注入
  • 手动模式

    • XML 资源配置元信息

    • Java 注解配置元信息

    • API 配置元信息

  • 自动模式

    • constructor

6.4.1 XML 方式

public class XmlDependencyConstructorInjectionDemo {
    public static void main(String[] args) {
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
        reader.loadBeanDefinitions("classpath:dependency-constructor-injection.xml");
        System.out.println(factory.getBean(UserHolder.class));
    }
}


​
    
​
    
        
    

6.4.2 Java 注解方式

public class AnnotationDependencyConstructorInjectionDemo {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(AnnotationDependencyConstructorInjectionDemo.class);
​
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context);
        reader.loadBeanDefinitions("classpath:beans-ioc-lookup.xml");
​
        context.refresh();
​
        System.out.println(context.getBean(UserHolder.class));
​
        context.close();
    }
​
    @Bean
    public UserHolder userHolder(User user) {
         // 构造器方式
         return new UserHolder(user);
    }
}

6.4.3 API 方式

public class ApiDependencyConstructorInjectionDemo {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
​
        context.registerBeanDefinition("userHolder", createBeanDefinitionUserHolder());
​
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context);
        reader.loadBeanDefinitions("classpath:beans-ioc-lookup.xml");
​
        context.refresh();
​
        System.out.println(context.getBean(UserHolder.class));
​
        context.close();
    }
​
    private static BeanDefinition createBeanDefinitionUserHolder() {
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(UserHolder.class);
​
        // 按照构造器参数顺序进行设置
        builder.addConstructorArgReference("superUser");
​
        return builder.getBeanDefinition();
    }
}

6.4.4 自动注入方式

public class AutowiringByConstructorDependencySetterInjectionDemo {
    public static void main(String[] args) {
        DefaultListableBeanFactory context = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context);
        reader.loadBeanDefinitions("autowiring-dependency-constructor-injection.xml");
        System.out.println(context.getBean(UserHolder.class));
    }
}


​
    
​
    
6.5 字段注入

只有手动注入方式,以注解为主:

  • @Autowired(忽略静态字段)

  • @Resource

  • @Inject

public class AnnotationDependencyFieldInjectionDemo {
​
    // Autowire 会忽略静态字段
    @Autowired
    private UserHolder userHolder;
​
    @Resource
    private UserHolder userHolder2;
​
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(AnnotationDependencyFieldInjectionDemo.class);
​
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context);
        reader.loadBeanDefinitions("classpath:beans-ioc-lookup.xml");
​
        context.refresh();
​
        AnnotationDependencyFieldInjectionDemo demo = context.getBean(AnnotationDependencyFieldInjectionDemo.class);
        System.out.println(demo.userHolder);
        System.out.println(demo.userHolder == demo.userHolder2);
​
        context.close();
    }
​
    @Bean
    public UserHolder userHolder(User user) {
         // 构造器方式
         return new UserHolder(user);
    }
}
6.6 方法注入

手动注入:

  • @Autowired

  • @Resource

  • @Inject(可选)、

  • @Bean

public class AnnotationDependencyMethodInjectionDemo {
​
    private UserHolder userHolder;
​
    private UserHolder userHolder2;
​
    @Autowired
    public void initUserHolder(UserHolder userHolder) {
        this.userHolder = userHolder;
    }
​
    @Resource
    public void initUserHolder2(UserHolder userHolder2) {
        this.userHolder2 = userHolder2;
    }
​
    @Bean
    public UserHolder userHolder(User user) {
        // 构造器方式
        return new UserHolder(user);
    }
​
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(AnnotationDependencyMethodInjectionDemo.class);
​
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context);
        reader.loadBeanDefinitions("classpath:beans-ioc-lookup.xml");
​
        context.refresh();
​
        AnnotationDependencyMethodInjectionDemo demo = context.getBean(AnnotationDependencyMethodInjectionDemo.class);
        System.out.println(demo.userHolder);
        System.out.println(demo.userHolder == demo.userHolder2);
​
        context.close();
    }
}
6.7 回调注入

Aware 系列接口回调注入(内建依赖)

内建接口说明
BeanFactoryAware获取 IoC 容器——BeanFactory
ApplicationContextAware获取 Spring 应用上下文——ApplicationContext 对象
EnvironmentAware获取 Environment 对象
ResourceLoaderAware获取资源加载器对象——ResourceLoader
BeanClassLoaderAware获取加载当前 Bean Class 的 ClassLoader
BeanNameAware获取当前 Bean的名称
MessageSourceAware获取 MessageSource 对象,用于 Spring 国际化
ApplicationEventPublisherAware获取 ApplicationEventPublisher 对象,用于 Spring 事件
EmbeddedValueResolverAware获取 StringValueResolver 对象,用于占位符处理
6.8 依赖注入类型选择
  • 低依赖:构造器注入(Spring 官方推荐注入方式)

  • 多依赖:Setter 方法注入

  • 便利性:字段注入(Spring 和 Spring 都不推荐使用字段注入)

  • 声明类:方法注入

6.9 基础类型注入
  • 原生类型(Primitive):boolean、byte、char、short、int、long、float、double

  • 标量类型(Scalar):Number、Character、Boolean、Enum、Locale、Charset、Currency、Properties、UUID

  • 常规类型(General):Object、String、TimeZone、Calendar、Optional等

  • Spring 类型:Resource、InputSource、Formatter



​
    
    
        
        
        
        
        
        
    
    
        
    
    
    
    
    
    
    
    
    
​
    
        
    
6.10 集合类型注入
  • 数组类型(Array):原生类型、标量类型、常规类型、Spring 类型

  • 集合类型(Collection)

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

    • Map:Properties



​
    
    
        
        
        
        
        
            
                BEIJING
                HANGZHOU
                SHANGHAI
            
        
        
            
                HANGZHOU
                SHANGHAI
            
        
        
            
                
                
            
        
        
    
    
        
    
    
    
    
    
    
    
    
    
​
    
        
    
6.11 限定注入
  • @Qualifier 限定注入

    • 通过 Bean 名称限定

    • 通过分组限定

  • 基于 @Qualifier 扩展限定

    • 自定义注解——如 Spring Cloud @LoadBalance

public class AnnotationQualifierDependencyInjectionDemo {
​
    @Autowired
    @Qualifier("user")
    private User user;
​
    @Autowired
    private Collection allUsers;
​
    @Autowired
    @Qualifier
    private Collection qualifiedUsers;
​
    // 通过使用 @Qualifier 进行逻辑分组
    @Bean
    @Qualifier
    public User user1() {
        User user = new User();
        user.setName("user1");
        return user;
    }
​
    // 通过使用 @Qualifier 进行逻辑分组
    @Bean
    @Qualifier
    public User user2() {
        User user = new User();
        user.setName("user2");
        return user;
    }
​
​
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(AnnotationQualifierDependencyInjectionDemo.class);
​
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context);
        reader.loadBeanDefinitions("classpath:beans-ioc-lookup.xml");
        context.refresh();
​
        AnnotationQualifierDependencyInjectionDemo bean = context.getBean(AnnotationQualifierDependencyInjectionDemo.class);
        System.out.println(bean.user);
        System.out.println(bean.allUsers);
        System.out.println(bean.qualifiedUsers);
​
        context.close();
    }
}
6.12 延迟注入
  • 使用 API ObjectFactory 实现延迟注入

    • 单一类型

    • 集合类型

  • 使用 API ObjectProvider 实现延迟注入(推荐使用,安全)

    • 单一类型

    • 集合类型

6.13 依赖处理过程
  • 入口——DefaultListableBeanFactory#resolveDependency

  • 依赖描述符——DependencyDescriptor

  • 自动绑定候选对象处理器——AutowireCandidateResolver

6.14 @Autowire 注入原理
  • 元信息解析(MergedBeanDefinitionPostProcessor#postProcessorMergedBeanDefinition 方法中进行)

  • 依赖查找(注入过程中包含依赖查找)

  • 依赖注入(字段、方法)(AutowiredAnnotationBeanPostProcessor#postProcessorProperties 方法中进行)

6.15 JSR-330 @Inject 注入原理
public AutowiredAnnotationBeanPostProcessor() {
    this.autowiredAnnotationTypes.add(Autowired.class);
    this.autowiredAnnotationTypes.add(Value.class);
    try {
        this.autowiredAnnotationTypes.add((Class)
                                          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.
    }
}

@Inject 注解跟 @Autowired 注解注入流程是相似的,如果引入了 JSR-330 jar 包,就可以使用该注解进行注入

6.16 Java 通用注解注入原理(@Resource等)

CommonAnnotationBeanPostProcessor(比 AutowiredAnnotationBeanPostProcessor 支持更多的注解,除了注入注解,还支持生命周期注解)

  • 注入注解

    • javax.xml.ws.WebServiceRef

    • javax.ejb.EJB

    • javax.annotation.Resource

  • 生命周期注解(构建 LifecycleElement)

    • javax.annotation.PostConstructor

    • javax.annotation.PreDestroy

6.17 自定义依赖注入注解
  • 基于 AutowiredAnnotationBeanPostProcessor 实现

  • 自定义实现

    • 生命周期处理

      • InstantiationAwareBeanPostProcessor

      • MergedBeanDefinitionPostProcessor

    • 元数据

      • InjectElement

      • InjectMetadata

6.18 面试题

6.18.1 有多少种依赖注入方式

  • 构造器注入(少依赖,强制依赖)

  • Setter 注入(多依赖,非强制依赖)

  • 字段注入

  • 方法注入

  • 接口回调注入

6.18.2 你偏好构造器注入还是 Setter 注入?

两种依赖注入均可使用,如果是必须依赖,推荐使用构造器注入,Setter注入可选依赖

依赖注入少用外部注解,包括 Java 注解和 Spring 注解,sh奥用注解就少依赖,使用原始 API、原始构造器参数来进行操作,可以解决依赖问题,同时还能解决线程安全问题(构造器可以确保线程安全问题)

6.18.3 Spring 依赖注入来源有哪些?

依赖查找通过 getBean,依赖注入通过 resolveDependency

  • 自定义 Bean(XML、注解、API)

  • 内建 Bean

  • 内建依赖

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/851909.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号