• Spring详解(七)----Spring Bean的自动装配(基于XML的方式)


    1、自动装配的几种方式

           上一章介绍 Bean 的装配都是在 Spring 容器中手动完成属性的装配,而在Spring 容器中给我们提供了完成 bean 之间的自动装配的功能(即对象类型的自动装配),这样的好处就是有助于减少编写一个大的基于 Spring 的应用程序的 XML 配置的数量,因为在稍微大一点的项目中,一个被引用的bean的id改变了,那么需要修改所有引用了它的id。Spring框架默认是不支持自动装配的,我们可以使用Spring的配置文件中< bean >元素的 autowire 属性为一个 bean 定义指定自动装配模式。其中<bean>元素中的autowire属性有5个可选值,如下:

    • no:默认的设置,表示不启用自动装配,需要我们手动通过"ref"属性手动完成装配。
    • byName:通过属性名称自动装配,如果一个JavaBean中的属性名称与Bean的id 相同,则自动装配这个Bean到JavaBean的属性中。Spring会查找该JavaBean中所有的set方法名,获得将set去掉并且首字母小写的字符串,然后去Spring容器中寻找是否有此字符串名称id 的Bean。如果有则就注入,如果没有则注入动作将不会执行。
    • byType:通过属性类型自动装配。Spring会在容器中查找JavaBean中的属性类型与Bean的类型一致的Bean,并自动装配这个Bean到JavaBean的属性中,如果容器中包含多个这个类型的Bean,Spring将抛出异常。如果没有找到这个类型的Bean,那么注入动作将不会执行。
    • constructor:类似于byType,也是通过类型自动装配,但是它是通过构造方法的参数类型来匹配。Spring会寻找与该JavaBean构造方法的各个参数类型相匹配的Bean,然后通过构造函数注入进来。如果在Spring容器中没有找一个构造函数参数类型的 Bean,则会报错。
    • autodetect:表示在constructor和byType之间自动的选择注入方式(spring5.x已经没有了)。首先尝试通过 constructor 来自动装配,如果它不执行,则Spring 尝试通过 byType 来自动装配。
    • default:由上级标签beans的default-autowire属性确定。

    2、举例代码样例

           User类代码:

    /**
     * 用户实体类
     */
    public class User {
        private int userId;
        private String userName;
        private int userAge;
        private String userPwd;
        private String userAddress;
        //女朋友
        private GirlFriend girlFriend;
    
        public User() {
        }
    
        public User(int userId, String userName, int userAge, String userPwd,
                    String userAddress, GirlFriend girlFriend) {
            this.userId = userId;
            this.userName = userName;
            this.userAge = userAge;
            this.userPwd = userPwd;
            this.userAddress = userAddress;
            this.girlFriend = girlFriend;
        }
    
        //getter、setter、toString方法省略......
    }

           GirlFriend类代码:

    /**
     * GirlFriend实体
     */
    public class GirlFriend {
        private String girlName;
        private int girlAge;
        private String girlHeight;
    
        //getter、setter、toString方法省略......
    }

           测试代码:

    /**
     * 测试代码
     */
    public class SpringTest {
        public static void main(String[] args) {
            //1.初始化Spring容器,加载配置文件
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
            //2.通过容器获取实例,getBean()方法中的参数是bean标签中的id
            User user =  applicationContext.getBean("user", User.class);
            //3.调用实例中的属性
            System.out.println(user.getUserName()+"-----"+user.getGirlFriend());
        }
    }

    3、byName装配

           byName装配是根据属性的名称自动装配,如果一个JavaBean中的属性名称与Bean的id 相同,则自动装配这个Bean到JavaBean的属性中。Spring会查找该JavaBean中所有的set方法名,获得将set去掉并且首字母小写的字符串,然后去Spring容器中寻找是否有此字符串名称id 的Bean。如果有则就注入,如果没有则注入动作将不会执行。

           applicationContext.xml配置内容为:

    image

          运行测试代码,查看控制台输出:

    image

           可以发现根据名称自动配置成功了,User类中girlFriend属性自动找到了 id 为 girlFriend 的 Bean,而配置文件中如果没有定义 id 为 girlFriend 的 Bean则会自动装配失败,例如,修改xml中Bean id为girlFriend1,更改后如下所示:

    image

           再次运行测试代码,查看控制台输出:

    image

           可以发现如果没有找到这个bean,那么就不装配。

    4、byType装配

           byType装配表示通过属性类型自动装配。Spring会在容器中查找JavaBean中的属性类型与Bean的类型一致的Bean,并自动装配这个Bean到JavaBean的属性中,如果容器中包含多个这个类型的Bean,Spring将抛出异常。如果没有找到这个类型的Bean,那么注入动作将不会执行。

          我们将前面Spring配置文件中的autowire属性修改为byType:

    image

          运行测试代码,查看控制台输出:

    image

           注意:使用byType首先需要保证同一类型的Bean在Spring容器中是唯一的,若不唯一则会产生歧义,Spring容器不知道选择哪个实例注入,所以后面会报异常。

           假如这里出现了两个,那么 Spring 则不知道选择哪个,此时会报错:

    image

           运行测试代码,查看控制台输出:

    image

           所以,如果一旦选择了byType类型的自动装配,就必须确认配置文件中每个数据类型定义一个唯一的bean。

    5、constructor装配

           constructor装配类似于byType,也是通过类型自动装配,但是它是通过构造方法的参数类型来匹配。Spring会寻找与该JavaBean构造方法的各个参数类型相匹配的Bean,然后通过构造函数注入进来。如果在Spring容器中没有找一个构造函数参数类型的 Bean,则会报错。

           applicationContext.xml配置内容为:

    image

           运行测试代码,查看控制台输出:

    image

           constructor自动装配具有和byType自动装配相同的局限性,就是当发现多个Bean匹配该JavaBean构造方法的类型时,Spring不知道用哪个Bean来装配,所以会导致装配失败。此外,如果一个JavaBean有多个构造方法,它们都满足自动装配的条件时,那么Spring也不会知道构造方法更适合使用,所以我们基本不会使用constructor装配。

    6、default装配

           default装配表示由父级标签beans的default-autowire属性来配置。如果beans标签上设置了default-autowire属性,那么default-autowire属性会统一配置当前beans中的所有bean的自动装配方式。

    image

    • 如果子标签<bean>没有单独的设置autowire属性,那么将采用父标签的default-autowire属性的模式。
    • 如果子标签<bean>单独设置了autowire属性,则采用自己的模式。

    7、Bean自动装配的补充

           ①、上述的讲到byType和constructor装配是支持数组和强类型集合(即指定了集合元素类型)。如bean A有个属性定义是List<Foo>类型,Spring会在容器中查找所有类型为Foo的bean,注入到该属性。记住是Foo,不是List。另外如果集合是Map集合,那么Map的key必须是String类型,Spring会根据value的类型去匹配。例如有属性bean A中有一个属性为Map<String, Foo> p,容器中有bean B和C类型均为Foo,那么A实例化完成后,p属性的值为:{"B":B的实例对象,"C":C的实例对象}。

           ②、虽然autowrie给我们带来配置的便利性,但是也有缺点,比如会导致bean的关系没那么显而易见,所以用autowire还是ref还是需要根据项目来决定。

           ③、autowire-candidate:前面我们说到配置有autowire属性的bean,Spring在实例化这个bean的时候会在容器中查找匹配的bean对autowire bean进行属性注入,这些被查找的bean我们称为候选bean。作为候选bean,我凭什么就要被你用,老子不给你用。所以候选bean给自己增加了autowire-candidate="false"属性(默认是true),那么容器就不会把这个bean当做候选bean了,即这个bean不会被当做自动装配对象。同样,<beans/>标签可以定义default-autowire-candidate="false"属性让它包含的所有bean都不做为候选bean。我的地盘我做主。


           参考资料:

  • 相关阅读:
    android 自定义动画4 RotateAnimation源码分析
    Android 绘图 阴影制作(Shadow)
    view, surfaceView, invalidate, postInvalidate, 刷新屏幕
    android database 常用字段描述
    Android标题栏进度指示器使用
    ThumbnailUtils Android2.2新增类
    Android 重力感应 测试代码
    Android中内嵌字体实现个性化
    Android中悬浮窗口
    Android布局Java代码构造法
  • 原文地址:https://www.cnblogs.com/tanghaorong/p/14157608.html
Copyright © 2020-2023  润新知