• Spring学习(六)bean装配详解之 【通过注解装配 Bean】【基础配置方式】


    通过注解装配 Bean

    1、前言

    优势

    1.可以减少 XML 的配置,当配置项多的时候,XML配置过多会导致项目臃肿难以维护

    2.功能更加强大,既能实现 XML 的功能,也提供了自动装配的功能,采用了自动装配后,程序猿所需要做的决断就少了,更加有利于对程序的开发,这就是“约定优于配置”的开发原则

    IOC发现Bean的两种方式

    组件扫描:通过定义资源的方式,让 Spring IoC 容器扫描对应的包,从而把 bean 装配进来。

    自动装配:通过注解定义,使得一些依赖关系可以通过注解完成。

    注解分为两类

      一类是使用Bean,即是把已经在xml文件中配置好的Bean拿来用,完成属性、方法的组装;比如@Autowired , @Resource,可以通过byTYPE(@Autowired)、byNAME(@Resource)的方式获取Bean;

      一类是注册Bean,@Component , @Repository , @ Controller , @Service , @Configration这些注解都是把你要实例化的对象转化成一个Bean,放在IoC容器中,等你要用的时候,它会和上面的@Autowired , @Resource配合到一起,把对象、属性、方法完美组装。

    2、使用@Compoent 装配 Bean

    我们把之前创建的 Student 类改一下:

    package pojo;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;
    
    @Component(value = "student1")
    public class Student {
    
        @Value("1")
        int id;
        @Value("student_name_1")
        String name;
    
        // getter and setter
    }

     解释一下:

    @Component注解:

      表示 Spring IoC 会把这个类扫描成一个 bean 实例,而其中的 value 属性代表这个类在 Spring 中的 id,这就相当于在 XML 中定义的 Bean 的 id:<bean id="student1" class="pojo.Student" />,也可以简写成 @Component("student1"),甚至直接写成 @Component ,对于不写的,Spring IoC 容器就默认以类名来命名作为 id,只不过首字母小写,配置到容器中。

    @Value注解:

      表示值的注入,跟在 XML 中写 value 属性是一样的。

        这样我们就声明好了我们要创建的一个 Bean,就像在 XML 中写下了这样一句话:

    <bean name="student1" class="pojo.Student">
        <property name="id" value="1" />
        <property name="name" value="student_name_1"/>
    </bean>

       但是现在我们声明了这个类,并不能进行任何的测试,因为 Spring IoC 并不知道这个 Bean 的存在,这个时候我们可以使用一个 StudentConfig 类去告诉 Spring IoC :

    package pojo;
    import org.springframework.context.annotation.ComponentScan;
    
    @ComponentScan
    public class StudentConfig {
    }

    这个类十分简单,没有任何逻辑,但是需要说明两点:

    1、该类和 Student 类位于同一包名下

    2、@ComponentScan注解:

    代表进行扫描,默认是扫描当前包的路径,扫描所有带有 @Component 注解的 POJO。

    PS:也可以用XML来配置扫描路径,不过推荐使用注解的形式

     

      这样一来,我们就可以通过 Spring 定义好的 Spring IoC 容器的实现类——AnnotationConfigApplicationContext 去生成 IoC 容器了:

    ApplicationContext context = new AnnotationConfigApplicationContext(StudentConfig.class);
    Student student = (Student) context.getBean("student1", Student.class);
    student.printInformation();

      这里可以看到使用了 AnnotationConfigApplicationContext 类去初始化 Spring IoC 容器,它的配置项是 StudentConfig 类,这样 Spring IoC 就会根据注解的配置去解析对应的资源,来生成 IoC 容器了。

    明显的弊端:

    • 对于 @ComponentScan 注解,它只是扫描所在包的 Java 类,但是更多的时候我们希望的是可以扫描我们指定的类
    • 上面的例子只是注入了一些简单的值,测试发现,通过 @Value 注解并不能注入对象

    @Component 注解存在着两个配置项:

    basePackages:它是由 base 和 package 两个单词组成的,而 package 还是用了复数,意味着它可以配置一个 Java 包的数组,Spring 会根据它的配置扫描对应的包和子包,将配置好的 Bean 装配进来

    basePackageClasses:它由 base、package 和 class 三个单词组成,采用复数,意味着它可以配置多个类, Spring 会根据配置的类所在的包,为包和子包进行扫描装配对应配置的 Bean

    我们来试着重构之前写的 StudentConfig 类来验证上面两个配置项:

    package pojo;
    import org.springframework.context.annotation.ComponentScan;
    
    @ComponentScan(basePackages = "pojo")//配置扫描pojo包
    public class StudentConfig {
    }
    
    //  —————————————————— 【 宇宙超级无敌分割线】—————————————————— 
    package pojo;
    
    import org.springframework.context.annotation.ComponentScan;
    
    @ComponentScan(basePackageClasses = pojo.Student.class)//配置扫描pojo包下名为Student的类
    public class StudentConfig {
    }

    对于 【basePackages】 和 【basePackageClasses】 的选择问题:

      【basePackages】 的可读性会更好一些,所以在项目中会优先选择使用它,但是在需要大量重构的工程中,尽量不要使用【basePackages】,因为很多时候重构修改包名需要反复地配置,而 IDE 不会给你任何的提示,而采用【basePackageClasses】会有错误提示。

    3、自动装配——@Autowired

    定义:由 Spring 自己发现对应的 Bean,自动完成装配工作的方式(根据类型查找

    例子解析:

    1.先在 Package【service】下创建一个 StudentService 接口:

    package service;
    
    public interface StudentService {
        public void printStudentInfo();
    }

    PS:使用接口是 Spring 推荐的方式,这样可以更为灵活,可以将定义和实现分离

    2.为上面的接口创建一个 StudentServiceImp 实现类:

    @Component("studentService")//表示IoC把这个类扫描成一个bean实例(这里简写了,括号内等同于XML配置方式时的id)
    public class StudentServiceImp implements StudentService {
    
        @Autowired//Spring自己发现bean并装配
        private Student student = null;
    
        public void printStudentInfo() {
            System.out.println("学生的 id 为:" + student.getName());
            System.out.println("学生的 name 为:" + student.getName());
        }
    }

    3.编写测试类:

    // 第一步:修改 StudentConfig 类,告诉 Spring IoC 在哪里去扫描它:
    package pojo;
    
    import org.springframework.context.annotation.ComponentScan;
    
    @ComponentScan(basePackages = {"pojo", "service"})
    public class StudentConfig {
    }
    
    // 或者也可以在 XML 文件中声明去哪里做扫描
    <context:component-scan base-package="pojo" />
    <context:component-scan base-package="service" />
    
    // 第二步:编写测试类:
    package test;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import pojo.StudentConfig;
    import service.StudentService;
    import service.StudentServiceImp;
    
    public class TestSpring {
    
        public static void main(String[] args) {
            // 通过注解的方式初始化 Spring IoC 容器
            ApplicationContext context = new AnnotationConfigApplicationContext(StudentConfig.class);
            StudentService studentService = context.getBean("studentService", StudentServiceImp.class);
            studentService.printStudentInfo();
        }
    }

    小结:

      @Autowired 注解表示在 Spring IoC 定位所有的 Bean 后,再根据类型寻找资源,然后将其注入。

      过程:定义 Bean ——》 初始化 Bean(扫描) ——》 根据属性需要从 Spring IoC 容器中搜寻满足要求的 Bean ——》 满足要求则注入

      问题: IoC 容器可能会寻找失败,此时会抛出异常(默认情况下,Spring IoC 容器会认为一定要找到对应的 Bean 来注入到这个字段,但有些时候并不是一定需要,比如日志)

      解决: 通过配置项 required 来改变,比如 @Autowired(required = false),该属性可控制IOC容器找不到Bean时不报错。

      PS:@Autowired 注解不仅仅能配置在属性之上,还允许方法配置,常见的 Bean 的 setter 方法也可以使用它来完成注入,总之一切需要 Spring IoC 去寻找 Bean 资源的地方都可以用到

  • 相关阅读:
    用OpenGL简单编写的一个最简单贪吃蛇游戏
    Python lambda map filter reduce
    Hadoop Python MapReduce
    Python faker生成数据
    Pandas数据清洗
    PySpark与jupyer notebook
    虚拟机与宿主机网络共享
    集合覆盖问题与贪婪算法
    最快路径与狄克斯特拉
    最短路径问题与广度优先搜索
  • 原文地址:https://www.cnblogs.com/riches/p/11521428.html
Copyright © 2020-2023  润新知