• Spring 框架学习(七)---- bean自动装配、注解开发


    Spring 框架学习(七)---- bean自动装配、注解开发


    一、Bean的自动装配


    先说一下什么叫自动装配

    自动装配就是给bean中的属性进行设置值进行注入,如果是引用类型的话,spring会在上下文中进行查找进行装配属性。

    我们先搭建一个可以实现装配的环境


    Fish类,拥有swim方法

    package com.bit.pojo;
    import lombok.Getter;
    import lombok.Setter;
    import lombok.ToString;
    
    @Setter
    @Getter
    @ToString
    public class Fish {
        public void swim(){
            System.out.println("小鱼会游泳!");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    Bird类,拥有Fly方法

    package com.bit.pojo;
    import lombok.Getter;
    import lombok.Setter;
    import lombok.ToString;
    
    @Setter
    @Getter
    @ToString
    public class Bird {
        public void fly(){
            System.out.println("小鸟会飞!");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    Peopel类,Fish和Bird都是人的宠物,所以这两个对象作为属性要装配到peopel类中

    package com.bit.pojo;
    
    import lombok.Getter;
    import lombok.Setter;
    import lombok.ToString;
    
    @Setter
    @Getter@ToString
    public class Peopel {
        private Bird bird;
        private Fish fish;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    1、在xml中显式的配置


    (1)ByName


    首先将Fish类和Bird类注册到bean中,在peopel的bean中配置autoWird 类型根据名字进行自动装配

    <bean id="fish" class="com.bit.pojo.Fish"/>
    
    <bean id="bird" class="com.bit.pojo.Bird"/>
    
    <bean id="peopel" class="com.bit.pojo.Peopel" autowire="byName"/>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    这里的autowird 后面写 byName 就是根据set后面跟的名字在上下文中进行查找,然后进行装配。

    那么如果byName 没有在上下文中查找这个名字呢?

    <bean id="fish2222222" class="com.bit.pojo.Fish" primary="true"/>
    
    <bean id="bird" class="com.bit.pojo.Bird"/>
    
    <bean id="peopel" class="com.bit.pojo.Peopel" autowire="byName"/>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    那么就会报错,Fish属性对象根据Name没有查找到,所以报空指针异常


    在这里插入图片描述

    如果我们bean的id与set后面的值不一致该怎么进行自动装配呢?


    (2)ByType


    <bean id="fish2222222" class="com.bit.pojo.Fish"/>
    
    <bean id="bird2222222" class="com.bit.pojo.Bird"/>
    
    <bean id="peopel" class="com.bit.pojo.Peopel" autowire="byType"/>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这里autoWird后面跟的 byType 是根据属性的类型进行查找,所以在上面的xml文件中 id全部与set后面跟的值不一致,我们看能否运行成功


        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
            Peopel peopel = context.getBean("peopel", Peopel.class);
            peopel.getBird().fly();
            peopel.getFish().swim();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    查看运行结果

    在这里插入图片描述

    如果一个类型的bean有多个,能查找成功吗?


    答案是会报错,不管是 byName 还是 byType 必须得找到唯一的bean才能装配成功。我们可以在同一类型的某个bean中加上primary:ture,那么可以运行成功

    <bean id="fish1" class="com.bit.pojo.Fish" primary="true"/>
        <bean id="fish2" class="com.bit.pojo.Fish"/>
    
    <bean id="bird2222222" class="com.bit.pojo.Bird"/>
    
    <bean id="peopel" class="com.bit.pojo.Peopel" autowire="byType"/>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    总结


    1.byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的bean id

    2.byType: 会自动在容器上下文中查找,和自己对象属性类型相同的bean


    注意点

    • Byname的时候,需要保证所有bean的id唯一,并且这个bean的id需要和自动注入属性的set方法后面的字段一致

    • ByType的时候,需要保证所有bean的class唯一,并且这个bean的class需要和 注入属性的类型全限定名一致。


    2、隐式的自动装配【重要】


    使用注解进行开发

    在使用注解之前,我们需要进行配置

    • 加入contetx约束

    • 加入注解支持

    • 加入扫描(扫描包下的注解)


    Spring 支持注解的代码

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context
            https://www.springframework.org/schema/context/spring-context.xsd">
    
        <!--    1.在上面加上 context的xml约束-->
        
    
        <!--    2.加上注解支持-->
        <context:annotation-config/>
        
        <!--    3.最好加上扫描注解的xml-->
        <context:component-scan base-package="包名"/>
    
    </beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    (1)@Autowired


    @Autowired 是默认根据ByType进行配置,如果有多个类型的bean,那么

    直接在属性上用即可,也可以在set方法上面使用

    使用Autowired我们可以不用编写set方法了,前提是你这个自动装配的属性在 Ioc 中已经存在了,且符合属性ByType唯一


    注意点

    • 默认是 byType 的方式进行注入

    • 如果有多个同一类型的bean,通过byName进行查找

    • 如果按照名字进行查找

    只是在xml文件中注册bean对象

        <bean id="bird" class="com.bit.pojo.Bird"/>
        <bean id="bird1" class="com.bit.pojo.Bird"/>
    
        <bean id="fish" class="com.bit.pojo.Fish"/>
        <bean id="fish1" class="com.bit.pojo.Fish"/>
        
        <bean id="peopel" class="com.bit.pojo.Peopel"/>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    Peopel类中对 两个属性标记Autowired注解

    package com.bit.pojo;
    
    import lombok.Getter;
    import lombok.Setter;
    import lombok.ToString;
    import org.springframework.beans.factory.annotation.Autowired;
    
    @Setter
    @Getter
    @ToString
    public class Peopel {
        
        @Autowired
        private Bird bird;
        
        @Autowired
        private Fish fish;
        
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    测试是否装配成功

        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
            Peopel peopel = context.getBean("peopel", Peopel.class);
            peopel.getBird().fly();
            peopel.getFish().swim();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    运行成功。

    在这里插入图片描述

    Autowired注解默认是按照 byType 进行查找的,

    如果在容器中存在多个同一类型的bean,那么继续按照 byName 的方式进行查找,进行装配,

    如果都不符合那么发生异常报错。

    如果都不符合的情况下,我们还想要进行装配,那么怎么操作呢?

    答案就是搭配@Qualifier进行使用


    @Qualifier


    如果在配置文件中,有多个相同类型的bean,同时bean的id与set后面的字段不一致,如下图

        <bean id="bird1" class="com.bit.pojo.Bird"/>
        <bean id="bird2" class="com.bit.pojo.Bird"/>
    
        <bean id="fish1" class="com.bit.pojo.Fish"/>
        <bean id="fish2" class="com.bit.pojo.Fish"/>
    
        <bean id="peopel" class="com.bit.pojo.Peopel"/>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    可以使用 @Autowired @Qualifier 进行搭配使用查找到上下文当中唯一的id

    package com.bit.pojo;
    
    import lombok.Getter;
    import lombok.Setter;
    import lombok.ToString;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    
    @Setter
    @Getter
    @ToString
    public class Peopel {
    
        @Autowired
        @Qualifier(value = "bird1")
        private Bird bird;
    
        @Autowired
        @Qualifier(value = "fish1")
        private Fish fish;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • @Qualifier 必须和@Autowired进行搭配使用

    • 按照@Qualifier 中的value进行设置,查找上下文中id为 value的 唯一的bean


    @Value


    字段属性标记了这个注解,可以在注解后面的括号中进行这只该属性的值。

    package com.bit.pojo;
    
    import lombok.Getter;
    import lombok.Setter;
    import lombok.ToString;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.beans.factory.annotation.Value;
    
    @Setter
    @Getter
    @ToString
    public class Peopel {
    
        @Value("张三")
        private String name;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
      public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
            Peopel peopel = context.getBean("peopel", Peopel.class);
            System.out.println(peopel.getName());
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    也可以成功的注入属性

    在这里插入图片描述


    @Value 的作用

    @Value 就相当于在bean中的一个标签

    <property name="属性名" value="设置的值"/>
    
    • 1

    @Nullable


    字段属性标记了这个注解,说明这个字段可以为null。

    不是设置成null,而是可以为null

    package com.bit.pojo;
    
    import lombok.Getter;
    import lombok.Setter;
    import lombok.ToString;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.lang.Nullable;
    
    @Setter
    @Getter
    @ToString
    public class Peopel {
    
        @Value("张三")
        private String name;
        
        public void test(@Nullable String name){
            System.out.println(name);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    (2)@Resource


    这个注解与@Autowired的作用类似,@Resource是Java自带的注解,不是spring提供的,默认按照 byName进行装配

    如果bean的id都不符合的话,那么根据byType方式进行查找

    public class Peopel {
        @Resource
        private Bird bird;
    
        @Resource
        private Fish fish;
        
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
        <bean id="bird" class="com.bit.pojo.Bird"/>
        <bean id="fish" class="com.bit.pojo.Fish"/>
    
        <bean id="peopel" class="com.bit.pojo.Peopel"/>
    
    • 1
    • 2
    • 3
    • 4

    运行结果

    在这里插入图片描述


    如果在注解的后面什么都不加的话,默认按照set后面的字段名进行查找,如果在注解中加入name=“XXXX”,可以按照指定id进行查找。


    bean 的id名与set字段不一致

        <bean id="bird1111" class="com.bit.pojo.Bird"/>
        <bean id="fish1111" class="com.bit.pojo.Fish"/>
    
        <bean id="peopel" class="com.bit.pojo.Peopel"/>
    
    • 1
    • 2
    • 3
    • 4

    在Resource加上name=“”,查找指定ID的bean

    import javax.annotation.Resource;
    
    @Setter
    @Getter
    @ToString
    public class Peopel {
        @Resource(name = "bird1111")
        private Bird bird;
    
        @Resource(name = "fish1111")
        private Fish fish;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    同样也运行成功

    在这里插入图片描述


    注意点

    @Resource首先按照byName方式进行查找bean

    如果所有的bean id都不符合要求,那么按照byType 的方式进行查找,此时此类型只有一个bean才会装配成功

    @Autowired 和 @Resource的区别

    1、Autowired是spring提供的注解,Resource是Java自带的

    2、都是用来进行自动装配的,都可以放到属性字段和set方法上

    3、@Autowired默认通过ByType方式实现,如果有多个bean,按照ByName 方式查找

    4、@Resource默认通过ByName方式实现,如果找不到名字,那么按照ByType方式查找

    5、执行顺序不同,ByType和ByName的顺序不同。


    3、Java中显式配置


    使用Java进行配置,完全不需要使用xml配置文件


    (1)实体类,使用@Component交由Spring进行托管

    package com.bit.pojo;
    
    import lombok.Getter;
    import lombok.Setter;
    import lombok.ToString;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;
    
    @Component
    @Setter
    @Getter
    @ToString
    public class User {
    
        @Value("张三")
       private String name;
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    (2)创建一个类,在类上加上@Configuration 使得这个类变成一个配置类,完全等价于之前的xml配置文件。

    package com.bit.config;
    
    import com.bit.pojo.User;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    @ComponentScan("com.bit")
    public class Myconfig {
    
       @Bean
        public User getUser(){
           return new User();
       }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    @ComponentScan(“包名”) 对包下的类中的注解进行扫描,使其生效

    @Bean加在方法上面

    • 返回值相当于class,因为在上面有import导入了包名所以不需要全限定名

    • 方法名相当于id

    一个@Bean修饰的方法相当于下面这个xml语句

     <bean id="getUser" class="com.pojo.User"/>
    
    • 1

    (3)测试是否能够bean注册装配成功

    package com.bit.service;
    
    import com.bit.config.Myconfig;
    import com.bit.pojo.User;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
    public class UserService {
        public static void main(String[] args) {
            ApplicationContext context = new AnnotationConfigApplicationContext(Myconfig.class);
            User user1 = context.getBean("getUser",User.class);
            System.out.println(user1);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    (4)查看结果

    在这里插入图片描述


      具体的使用不在这里讲述了,spring 的项目通常由下,xml+注解来完成,在SpringBoot中也通常有纯Java的方式完成配置,所以在后面学习SpringBoot的时候再来详细说明。


    二 、使用注解开发


    1.在Spring4之后,必须导入aop的jar包才能使用注解

    在这里插入图片描述

    2.导入context约束

    3.使用注解要加入注解支持

    <context:annotation-config/>
    
    • 1

    4.指定要扫描的包,这个包下的所有注解就会生效

     <context:component-scan base-package="包名"/>
    
    • 1

    1、注册bean的注解


    @Component


    这个注解加在类上,说明这个类已经被spring管理了

    @Setter
    @Getter
    @ToString
    @Component
    public class Bird {
        public void fly(){
            System.out.println("小鸟会飞!");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在Bird类上加上@Component相当于下面的xml配置

    <bean id="bird" class="com.bit.pojo.Bird"/>
    
    • 1

    默认这个bean的id为类型名的首字母小写


    2、衍生的注解


    在web开发中,会按照mvc三层架构分层。

      其他的注解与这个注解的作用是相同的,但是因为类在不同包下的作用不同,所以使用的注解也不同,但是他们都是将该类交给spring进行管理的

    • controller 【@Controller】

    • dao 【@Repository】

    • service 【@Service】


    3、自动装配的注解


    @Autowired 和 @Resource 在上面自动装配已经说过了


    4、作用域的注解


    @Scope(value=“XXXX”)

    @Scope(value = "protoType")
    public class Peopel {
        @Resource(name = "bird1111")
        private Bird bird;
    
        @Resource(name = "fish1111")
        private Fish fish;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    可以在类上加上这个注解,来决定这个bean的作用域。


    5、xml配置与注解对比


    • xml更加万能,适用于任何场合,维护简单方便,也可以对复杂类型更好的管理配置

    • 注解 维护相对复杂!

    最佳实践: xml用来管理bean,注解只负责完成属性的注入

  • 相关阅读:
    C语言学习笔记(四)
    Java8--Stream的各种用法(二):collect、Collectors
    Java架构师分析和设计技术架构
    JavaScript中异步函数async、await
    非递归方式实现二叉树四种遍历
    如何获取l2行情接口?
    人工神经网络理论及应用,人工智能神经网络论文
    【Java】Arrays类常用方法
    上午面了个腾讯拿 38K 出来的,让我见识到了基础的天花板
    国内外数据保护(灾备、备份、恢复、复制、归档)厂商
  • 原文地址:https://blog.csdn.net/rain67/article/details/125338400