• Spring入门之四-------SpringIoC之其他知识点


    一、懒加载

    public class Bean1 {
    
        public Bean1() {
            System.out.println(this.getClass().getSimpleName() + ":" + this.toString() + " has been created");
        }
    }
    Bean1
    public class Bean2 {
    
        public Bean2() {
            System.out.println(this.getClass().getSimpleName() + ":" + this.toString() + " has been created");
        }
    }
    Bean2
    <bean id="bean1" class="com.imooc.springClass4.others.Bean1" lazy-init="false"/>
    <bean id="bean2" class="com.imooc.springClass4.others.Bean2" lazy-init="true"/>
    @Test
    public void testBean() throws Exception {
        final AbstractApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        System.out.println("============ApplicationContext has been create============");
    
        Bean1 bean1 = context.getBean("bean1", Bean1.class);
        System.out.println("bean1 = " + bean1);
        System.out.println();
    
        Bean2 bean2 = context.getBean("bean2", Bean2.class);
        System.out.println("bean2 = " + bean2);
        System.out.println();
    }

    输出

    Bean1:com.imooc.springClass4.others.Bean1@49438269 has been created
    ============ApplicationContext has been create============
    bean1 = com.imooc.springClass4.others.Bean1@49438269
    
    Bean2:com.imooc.springClass4.others.Bean2@2462cb01 has been created
    bean2 = com.imooc.springClass4.others.Bean2@2462cb01

    结论:bean1没有设定懒加载,所以Spring在加载上下文的时候就已经创建了bean1;bean2没有设定懒加载,所以bean2在被需要的时候才创建。

    如果想设定当前xml中所有的bean都默认开启懒加载,可通过设定default-lazy-init="false"实现:

    <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"
           default-lazy-init="false"
    >
    ...
    </beans>

    二、Bean别名

    public class Bean3 {
    
        public Bean3() {
            System.out.println(this.getClass().getSimpleName() + ":" + this.toString() + " has been created");
        }
    }
    Bean3

    方式一:通过name属性创建别名

    <bean id="bean3-1" name="bean3-2, bean3-3" class="com.imooc.springClass4.others.Bean3"/>

    上面代码表示:创建一个Bean3,id为bean3-1,再给取两个别名:bean3-2、bean3-3

    方式二:通过alias标签创建别名

    <alias name="bean3-1" alias="bean3-4"/>

    上面代码表示:给bean3-1取一个别名:bean3-4

    测试

    @Test
    public void testBean() throws Exception {
        final AbstractApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
    
        Bean3 bean3_1 = context.getBean("bean3-1", Bean3.class);
        System.out.println("bean3_1 = " + bean3_1);
        System.out.println();
    
        Bean3 bean3_2 = context.getBean("bean3-2", Bean3.class);
        System.out.println("bean3_2 = " + bean3_2);
        System.out.println();
    
        Bean3 bean3_3 = context.getBean("bean3-3", Bean3.class);
        System.out.println("bean3_3 = " + bean3_3);
        System.out.println();
    
        Bean3 bean3_4 = context.getBean("bean3-4", Bean3.class);
        System.out.println("bean3_4 = " + bean3_4);
        System.out.println();    
    }

    输出

    bean3_1 = com.imooc.springClass4.others.Bean3@1190200a
    bean3_2 = com.imooc.springClass4.others.Bean3@1190200a
    bean3_3 = com.imooc.springClass4.others.Bean3@1190200a
    bean3_4 = com.imooc.springClass4.others.Bean3@1190200a

    可以看到所有的bean3_?的地址都是一样的。

    三、引入其他xml

    public class Bean4 {
    
        public Bean4() {
            System.out.println(this.getClass().getSimpleName() + ":" + this.toString() + " has been created");
        }
    }
    Bean4

    resources目录下创建spring-1.xml,代码如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <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="bean4" class="com.imooc.springClass4.others.Bean4"/>
    </beans>

    调整之前的spring.xml,增加

    <import resource="spring-1.xml"/>

    测试

    @Test
    public void testBean() throws Exception {
        final AbstractApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
    Bean4 bean4
    = context.getBean("bean4", Bean4.class); System.out.println("bean4 = " + bean4); System.out.println(); }

    输出

    bean4 = com.imooc.springClass4.others.Bean4@6a2f6f80

    可以看到我们通过new ClassPathXmlApplicationContext("spring.xml")的方式引用spring.xml,由于spring.xml中import了spring-1.xml,所以spring-1.xml中定义的bean4也被实例化了。

    四、方法注入

    可能存在如下场景:Class A 的某个方法依赖于Class B的实例,Class A使用scope=singleton单例模式,但是Class A每次执行方法的时候都希望获取一个新的Class B的实例,这个时候就用到了方法注入。举例:

    public class Bean5 {
        public Bean5() {
            System.out.println(this.getClass().getSimpleName() + ":" + this.toString() + " has been created");
        }
    }
    public abstract class Bean6 {
    
        public Bean6() {
            System.out.println(this.getClass().getSimpleName() + ":" + this.toString() + " has been created");
        }
    
        protected abstract Bean5 createBean5();
        
        public void printBean5() {
            System.out.println("createBean5().toString() = " + createBean5().toString());
        }
    }

    从上面代码我们看到,Bean6的printBean5方法是依赖于Bean5的实例的,如果该方法每次执行都想获得一个Bean5的实例,那么:

    1. Bean6中声明一个abstract方法,返回Bean5
    2. Bean6的printBean5方法需要使用Bean5时直接饮用上面的abstract方法

    xml配置如下:注意bean5需要时prototype模式

    <bean id="bean5" class="com.imooc.springClass4.others.Bean5" scope="prototype"/>
    <bean id="bean6" class="com.imooc.springClass4.others.Bean6">
        <lookup-method name="createBean5" bean="bean5"/>
    </bean>

    测试:

    @Test
    public void testBean() throws Exception {
        final AbstractApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
       
        for (int i = 0; i < 10; i++) {
            Bean6 bean6 = context.getBean("bean6", Bean6.class);
            bean6.printBean5();
        }
    }

    输出:

    Bean5:com.imooc.springClass4.others.Bean5@19b843ba has been created
    createBean5().toString() = com.imooc.springClass4.others.Bean5@19b843ba
    Bean5:com.imooc.springClass4.others.Bean5@64ec96c6 has been created
    createBean5().toString() = com.imooc.springClass4.others.Bean5@64ec96c6
    Bean5:com.imooc.springClass4.others.Bean5@77659b30 has been created
    createBean5().toString() = com.imooc.springClass4.others.Bean5@77659b30
    Bean5:com.imooc.springClass4.others.Bean5@456d6c1e has been created
    createBean5().toString() = com.imooc.springClass4.others.Bean5@456d6c1e
    Bean5:com.imooc.springClass4.others.Bean5@1e13529a has been created
    createBean5().toString() = com.imooc.springClass4.others.Bean5@1e13529a
    ......

    可以看到Bean6.printBean5()方法每次拿到的Bean5都是不同的实例

    五、init-method和destroy-method

    1. 如果需要在Bean实例化完成之后执行一些逻辑,可以有如下两种方法:

    (1)使用init-method

    (2)让Bean实现InitializingBean接口

    2. 如果需要在Bean销毁之前执行一些逻辑,也有两种方法:

    (1)使用destroy-method

    (2)让Bean实现DisposableBean接口

    例如:

    public class Bean7 implements InitializingBean, DisposableBean {
    
        public Bean7() {
            System.out.println(this.getClass().getSimpleName() + ":" + this.toString() + " has been created");
        }
    
        public void onInit() {
            System.out.println(this.getClass().getSimpleName() + ":" + "onInit");
        }
    
        public void onDestroy() {
            System.out.println(this.getClass().getSimpleName() + ":" + "onDestroy");
        }
    
        public void afterPropertiesSet() throws Exception {
            System.out.println(this.getClass().getSimpleName() + ":" + "afterPropertiesSet");
        }
    
        public void destroy() throws Exception {
            System.out.println(this.getClass().getSimpleName() + ":" + "destroy");
        }
    }

    afterPropertiesSet()和destroy()是针对接口的实现。相应的xml配置:

    <bean id="bean7" class="com.imooc.springClass4.others.Bean7" init-method="onInit" destroy-method="onDestroy"/>

    测试:

    @Test
    public void testBean() throws Exception {
        final AbstractApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
    
        Bean7 bean7 = context.getBean("bean7", Bean7.class);
        System.out.println("bean7 = " + bean7);

    context.close(); }

    输出:

    Bean7:com.imooc.springClass4.others.Bean7@57cf54e1 has been created
    Bean7:afterPropertiesSet
    Bean7:onInit
    bean7 = com.imooc.springClass4.others.Bean7@57cf54e1
    Bean7:destroy
    Bean7:onDestroy

    如果想设定当前xml中所有的bean都有相同的init-method和destroy-method,可通过设定default-init-method="????"、default-destroy-method="????"实现:

    <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"
           default-init-method="onInit"
           default-destroy-method="onDestroy"
    >
    </beans>

    六、parent bean

    可能存在如下场景:有很多Class继承于Class B,且Class B有很多的property,当我们需要实例化很多Class B子类的时候,如果这些子类从Class B继承的propertiy值基本相同,那么通过xml创建这些子类是一件很繁重的事情,并且会存在很多类似的重复性的代码出现。这种情况下,有如下解决办法,举例说明:

    public class Bean8 {
    
        public Bean8() {
            System.out.println(this.getClass().getSimpleName() + ":" + this.toString() + " has been created");
        }
        private String name;
        private Integer age;
        //get/set...
    }
    public class Bean8_1 extends Bean8{
    
        public Bean8_1() {
            System.out.println(this.getClass().getSimpleName() + ":" + this.toString() + " has been created");
        }
        private String address;
        private Integer height;
        //get/set/toString...    
    }
    public class Bean8_2 extends Bean8{
    
        public Bean8_2() {
            System.out.println(this.getClass().getSimpleName() + ":" + this.toString() + " has been created");
        }
        private String email;
        private Integer weight;
        //get/set/toString...
    }
    <bean id="bean8" class="com.imooc.springClass4.others.Bean8" abstract="true">
        <property name="name" value="zhang3"/>
        <property name="age" value="33"/>
    </bean>
    <bean id="bean8_1" class="com.imooc.springClass4.others.Bean8_1" parent="bean8">
        <property name="age" value="34"/>
        <property name="address" value="JiangSu SuZhou"/>
        <property name="height" value="155"/>
    </bean>
    <bean id="bean8_2" class="com.imooc.springClass4.others.Bean8_2" parent="bean8">
        <property name="age" value="35"/>
        <property name="email" value="123@abc.com"/>
        <property name="weight" value="65"/>
    </bean>

    在xml中:

    1. 定义bean8,且设定abstracy=true,设定name和age的值
    2. 实例化bean8-1,且设定parent=bean8,重新设定age=34,设定address和height的值
    3. 实例化bean8-2,且设定parent=bean8,重新设定age=35,设定email和weight的值

    测试:

    @Test
    public void testBean() throws Exception {
        final AbstractApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
      
        Bean8_1 bean8_1 = context.getBean("bean8_1", Bean8_1.class);
        System.out.println("bean8_1 = " + bean8_1);
        Bean8_2 bean8_2 = context.getBean("bean8_2", Bean8_2.class);
        System.out.println("bean8_2 = " + bean8_2);
    }

    输出

    bean8_1 = Bean8_1{address='JiangSu SuZhou', height=155', name=zhang3', age=34}
    bean8_2 = Bean8_1{email='123@abc.com', weight=65', name=zhang3', age=35}

    这样,我们就可以将Bean8子类的属性值统一在bean8中赋值进去,且由于bean8被标注的abstract所以并不会被创建。

    另外,即使Bean8_1和Bean8_2没有继承于Bean8,但是Bean8_1和Bean8_2都有name和age属性,也可以用过类似的手段简化我们的代码,示例如下:

    public class Bean9_1 {
    
        public Bean9_1() {
            System.out.println(this.getClass().getSimpleName() + ":" + this.toString() + " has been created");
        }
    
        private String name;
        private Integer age;
        private String address;
        private Integer height;
    
        // get/set/toString......
    }
    public class Bean9_2{
    
        public Bean9_2() {
            System.out.println(this.getClass().getSimpleName() + ":" + this.toString() + " has been created");
        }
    
        private String name;
        private Integer age;
        private String email;
        private Integer weight;
    
        // get/get/toString...
    }
    <bean id="bean9" abstract="true">
        <property name="name" value="zhang3"/>
        <property name="age" value="33"/>
    </bean>
    <bean id="bean9_1" class="com.imooc.springClass4.others.Bean9_1" parent="bean9">
        <property name="age" value="34"/>
        <property name="address" value="JiangSu SuZhou"/>
        <property name="height" value="155"/>
    </bean>
    <bean id="bean9_2" class="com.imooc.springClass4.others.Bean9_2" parent="bean9">
        <property name="age" value="35"/>
        <property name="email" value="123@abc.com"/>
        <property name="weight" value="65"/>
    </bean>

    和之前bean8的区别就是,定义bean9的时候没有对应的Class

    测试:

    @Test
    public void testBean() throws Exception {
        final AbstractApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
     
        Bean9_1 bean9_1 = context.getBean("bean9_1", Bean9_1.class);
        System.out.println("bean9_1 = " + bean9_1);
        Bean9_2 bean9_2 = context.getBean("bean9_2", Bean9_2.class);
        System.out.println("bean9_2 = " + bean9_2);
    }

    输出

    bean9_1 = Bean9_1{name='zhang3', age=34, address='JiangSu SuZhou', height=155}
    bean9_2 = Bean9_2{name='zhang3', age=35, email='123@abc.com', weight=65}
  • 相关阅读:
    centos6 下erlang安装
    待研究
    关键字拦截查询
    获取CNVD的cookie
    adb pull 文件夹到电脑
    Linux中查看端口占用情况
    Running Tensorflow on AMD GPU
    验证码识别相关文章
    conda和pip相关操作
    windows安装pycrypto报错
  • 原文地址:https://www.cnblogs.com/LOVE0612/p/10050787.html
Copyright © 2020-2023  润新知