• Spring(一)- 初始 + DI+scope


    1、获取bean实例的三种方式

    1.1 id 属性

    1.1.1 jar

    Spring架构图
    <properties>
        <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
        <spring.version>4.3.18.RELEASEspring.version>
        <lombok.version>1.16.18lombok.version>
        <junit.version>4.11junit.version>
    
    properties>
    
    <dependencies>
        
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-beansartifactId>
            <version>${spring.version}version>
        dependency>
        
    
        
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-coreartifactId>
            <version>${spring.version}version>
        dependency>
        
    
        
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-contextartifactId>
            <version>${spring.version}version>
        dependency>
        
    
        
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-expressionartifactId>
            <version>${spring.version}version>
        dependency>
        
    
    dependencies>
    

    1.1.2 application.xml

    
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        
        <bean id="userOne" class="com.kgc.spring.bean.User">
            <property name="nickName" value="kh96_spring_one">property>
        bean>
    beans>
    

    标签:定义一个实例对象,会自动被创建 并 交给spring容器进行管理:

    • id 属性:被spring容器进行管理的实例的 唯一标识,整个容器中,只能是唯一的(不可重复);

    • class属性:指定创建当前实例对象的类型(全类名),spring底层是使用的 反射机制 ,根据指定的目标类型,创建目标实例(必须有 空参构造)

    • 子标签:给当前创建对象的属性值

      • name:指定对象的属性名
      • value: 给属性赋值

    1.1.3 测试

    @Test
    public void testSpringPrimer(){
        //1.创建spring的核心容器对象(引用上下文对象),解析spring的核心配置文件,将文件中的bean标签进行实例化(创建对象并赋值)
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    
        //2. 写法一: 从容器中获取实例对象,根据核心配置文件中,配置的bean标签的id属性值
        //            不足:强制转化,容易出现转换错误
        User userOne = (User) context.getBean("userOne");
        
        userOne.sayHello();
    
        //对比以前创建对象的写法(对象必须手动new创建,并手动赋值)
        User userOld = new User();
        userOld.setNickName("kh96_old");
        userOld.sayHello();
         
    }
    

    1.1.4 总结

    通过id属性,获取实例对象后需要强制转换,容易出现强制转化错误

    1.2 class 属性

    1.2.1 测试

    //写法二:从容器中获取实例对象,根据核心配置文件中,配置的bean标签的class属性指定的目标类型
    User userTwo = context.getBean(User.class);
    
    userTwo.sayHello();
    

    1.2.2 总结

    不足如果存在同类型的多个实例,会报异常

    1.2.2.1 application.xml

    当用多个同类型的实例:

    ...
    <bean id="userOne" class="com.kgc.spring.bean.User">
        <property name="nickName" value="kh96_spring_one">property>
    bean>
    
    
    <bean id="userTwo" class="com.kgc.spring.bean.User">
        <property name="nickName" value="kh96_spring_two">property>
    bean>
    ...
    
    1.2.2.2 测试
    User userTwo = context.getBean(User.class);
    

    会发生异常:

    NoUniqueBeanDefinitionException: No qualifying bean of type 'com.kgc.spring.bean.User' available: expected single matching bean but found 2: userOne,userTwo

    主要原因是由于只用class属性去获取实例,但是有多个相同类型的实例,所以无法确定你要获取的是哪一个

    1.3 id 属性 和 class 属性 (推荐)

    1.3.1 测试

    //写法三:从容器中获取实例对象,根据配置文件中,配置的bean标签的id属性值和class属性指定的目标类型
     User userTwoThree = context.getBean("userTwo", User.class);
    

    1.3.2 总结

    能够确定唯一实例,推荐使用;

    1.4 id 不能重复注意点

    配置文件中的id必须是唯一的;

    如果id不唯一:两个id一样的实例

    ...
    <bean id="userOne" class="com.kgc.spring.bean.User">
        <property name="nickName" value="kh96_spring_one">property>
    bean>
    <bean id="userOne" class="com.kgc.spring.bean.User">
        <property name="nickName" value="kh96_spring_one">property>
    bean>
    ...
    

    报错:

    BeanDefinitionParsingException: Configuration problem: Bean name 'userOne' is already used in this element

    提示 id 为 userOne 的实例已经存在;

    1.5 实例化时机

    初始化spring的容器对象时,会将核心配置文件中所有的bean实例化,不是使用哪个,创建哪个;

    2、DI

    IOC(控制反转是一种思想),DI是IOC的一种实现方式;

    2.1 set 方式注入

    2.1.1 实体

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
    
        //用户昵称
        //普通参数
        private String nickName;
    
        //私家车
        //实体参数
        private Car car;
    
        //喜欢的书
        //数组参数
        private String[] books;
    
        //爱好
        //list集合参数
        private List hobbies;
    
        //喜欢的游戏
        //set 集合
        private Set games;
    
        //卡包
        //map参数
        private Map cards;
    
        //在校信息
        //properties参数
        private Properties info;
    
        //是否有女朋友 (主要是演示赋值为null,其他类型都可以)
        //空参数注入
        private Boolean wife;
    
    }
    

    2.1.2 参数 注入

    ...
    
    <bean id="user01" class="com.kgc.spring.bean.User">
        
        <property name="nickName" value="小气鬼">property>
         
        
        
        <property name="car">
            
            <bean class="com.kgc.spring.bean.Car">
                <property name="brand" value="Bmw325">property>
                <property name="factory" value="华晨">property>
                <property name="price" value="300000">property>
            bean>
        property>
        
        <property name="books">
            <array>
                <value>红楼梦value>
                <value>水浒传value>
                <value>三国演义value>
                <value>西游记value>
            array>
        property>
        
        <property name="hobbies" >
            <list>
                <value>跑步value>
                <value>尤克里里value>
                <value>敲代码value>
            list>
        property>
        
        <property name="games">
            <set>
                <value>唱歌value>
                <value>跳舞value>
                <value>喝酒value>
            set>
        property>
        
        <property name="cards">
            <map>
                <entry key="身份证" value="1212121212121212">entry>
                <entry key="银行卡" value="1111111111111111">entry>
            map>
        property>
        
        <property name="info">
            <props>
                <prop key="学号">123456prop>
                <prop key="性别">prop>
                <prop key="姓名">化羽prop>
            props>
        property>
        
        <property name="wife">
            <null>null>
        property>
    bean>
    
    
    <bean id="carOne" class="com.kgc.spring.bean.Car">
        <property name="brand" value="Bmw325">property>
        <property name="factory" value="华晨">property>
        <property name="price" value="300000">property>
    bean>
    ...
    

    2.1.3 测试

    @Test
    public void testPramsDI(){
        User user01 = context.getBean("user01", User.class);
        //输入对象详情
        System.out.println(user01);
    }
    

    输出结果:

    User(
         nickName=小气鬼, 
         car=Car(brand=Bmw325, factory=华晨, price=300000.0), 
         books=[红楼梦, 水浒传, 三国演义, 西游记], 
         hobbies=[跑步, 尤克里里, 敲代码], 
         games=[唱歌, 跳舞, 喝酒], 
         cards={身份证=1212121212121212, 银行卡=1111111111111111}, 
         info={学号=1913001072, 性别=男, 姓名=化羽}, 
         wife=null
        )
    

    2.2 Constructor 构造器注入

    2.2.1 按照默认顺序 注入

    2.2.1.1 参数注入
    
    
    <bean id="carTwo" class="com.kgc.spring.bean.Car">
        <constructor-arg value="AudiA4">constructor-arg>
        <constructor-arg value="一汽">constructor-arg>
        <constructor-arg value="320000">constructor-arg>
    bean>
    
    2.2.1.2 测试
    @Test
    public void testSpringDIConstructor(){
        Car carTwo = context.getBean("carTwo", Car.class);
    
        //输出对象详情
        System.out.println(carTwo);
    }
    

    2.2.2 根据 参数的下标 和 类型 注入

    2.2.2.1 参数注入
    
    <bean id="carThree" class="com.kgc.spring.bean.Car">
        <constructor-arg index="0" value="BenzC200">constructor-arg>
        <constructor-arg index="1" value="北京">constructor-arg>
        <constructor-arg index="2" type="java.lang.Double" value="350000">constructor-arg>
    
    bean>
    
    2.2.2.2 测试
    @Test
    public void testSpringDIConstructor2(){
        Car carTwo = context.getBean("carThree", Car.class);
    
        //输入对象详情
        System.out.println(carTwo);
    }
    

    2.3 自定义 实体工厂bean

    自定义实体工厂bean ,必须实现FactoryBean接口

    普通bean 与 工厂bean 的区别:

    • 普通 bean:在配置文件中定义 bean 类型 就是 返回类型
    • 工厂 bean:在配置文件定义 bean 类型返回类型 不一样

    2.3.1 返回bean

    @Data
    @ToString
    public class Car {
        /*
         品牌
         */
        private String brand;
    
        /*
        厂商
         */
        private String factory;
    
        /*
        价格
         */
        private Double price;
    }
    

    2.3.2 实体工厂 bean

    • spring容器初始化时,创建当前工厂bean的实例对象,但是真实返回不是当前类的实例对象而是当前类的实例对象返回的目标实例对象(自定义);
    • 作用:可以在程序中,实现自定义创建实例(还可以增加业务逻辑处理),放入容器;
    • 存在的原因:spring框架对外开放了一个入口,可以让其他的开发人员参与到spring底层创建bean的实例过程中去给整合其他框架使用的,比如mybatis;
    public class CarFactoryBean implements FactoryBean {
        @Override
        public Car getObject() throws Exception {
            System.out.println("通过CarFactoryBean的实例对象的getObject方法:返回一个自定义的car的实例");
            return new Car("Byd唐","南京",2500000.0);
        }
    
        @Override
        public Class getObjectType() {
            //指定给Object方法返回的目标类型
            return Class.class;
        }
    
        @Override
        public boolean isSingleton() {
            //是否单例
            return false;
        }
    }
    

    2.3.3 工厂bean容器中添加自定义实例对象

    ...
    
    <bean id="carFactoryBean" class="com.kgc.spring.bean.CarFactoryBean">bean>
    ...
    

    2.3.4 测试

    @Test
    public void testSpringFactoryBean(){
        //从容器中获取工厂bean的实例对象
        Car car1 = context.getBean("carFactoryBean", Car.class);
        Car car2 = context.getBean("carFactoryBean", Car.class);
    
        //输出对象详情
        System.out.println(car 1); 
        //在容器中添加的实例是  CarFactoryBean 类型,返回的是 
        //Car(brand=Byd唐, factory=南京, price=2500000.0)
        System.out.println("car1 == car2 : " + ( car1 == car2)); 
        //false  说明工厂bean是多例的
    
    }
    

    3、scope 作用域

    • singleton 单例 (默认) 容器初始化之前创建;
    • prototype 多例 (手动设置) 使用到的时候才创建;

    3.1 singleton 单例

    这里区别于整个程序运行期间有且只有唯一的实例(单例模式-懒汉和饿汉);

    容器中bean的单例不是指当前类的实例在容器中,只有唯一的实例,而是当创建bean的实例时,此实例是单例(容器内唯一),但是同一个类的实例,容器中可以创建多个每个都是单例的

    3.1.1 配置bean

    
    <bean id="busTwo" class="com.kgc.spring.bean.Bus" scope="singleton">
        <property name="brand" value="金龙2">property>
        <property name="factory" value="厦门2">property>
        <property name="price" value="1200000">property>
    bean>
    

    3.1.2 测试

    @Test
    public void testScopeSingleton(){
        
        //从容器中,获取Bus的实例对象
        Bus busThree = context.getBean("busTwo", Bus.class);
        Bus busFour = context.getBean("busTwo", Bus.class);
    
        System.out.println(busThree);
        System.out.println(busFour);
    
        System.out.println("singleton busThree == busFour:"+(busThree == busFour));
    	//true
    }
    

    3.2 prototype 多例

    多例:prototype,不是spring容器中的默认作用,需要单独指定

    spring容器创建时,不会自动创建指定作用域为多例的bean的实例,而是每次通过getBean方法获取bean的实例,才会创建bean的实例

    3.2.1 配置bean

    
    <bean id="busThree" class="com.kgc.spring.bean.Bus" scope="prototype">
        <property name="brand" value="中通3">property>
        <property name="factory" value="山东3">property>
        <property name="price" value="1200000">property>
    bean>
    

    3.2.2 测试

    @Test
    public void testScopePrototype(){
        Bus busOne = context.getBean("busThree", Bus.class);
        Bus busTwo = context.getBean("busThree", Bus.class);
    
        //输入详情
        System.out.println(busOne);
        System.out.println(busTwo);
    
        System.out.println("prototype busOne == busTwo:"+(busOne == busTwo));
        //false
    
    }
    
  • 相关阅读:
    仪表板使用:汽车充电站
    htmx-使HTML更强大
    1400*C. Given Length and Sum of Digits...(贪心)
    【2-Docker安装部署ElasticSearch和Kibanan详细步骤】
    一文带你看透手机号码归属地
    关于pycharm中句号变成点的问题
    《Java并发编程的艺术》读书笔记 - 第一章 - 并发编程的挑战
    JAVA 网络编程(这章还有后续哦)
    SpringCloud学习笔记(三)
    全数字系列-麦克风K歌模组-搭配投影仪专业方案
  • 原文地址:https://www.cnblogs.com/xiaoqigui/p/16625420.html