ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

【java spring】bean的定义

2021-12-17 09:33:19  阅读:146  来源: 互联网

标签:java 单例 spring System stu bean Student 构造函数


单例bean和多例bean: 单例是指一个类的实例对象在一个程序周期中只能存在一个。多例则是可以存在多个实例对象。

在bean的xml定义中我们可以通过设置scope属性来指定一个bean是单例还是多例。其中prototype表示多例,singleton表示多例。
我们分别看一下两者具体用法。首先是单例:

<bean id="student_yqs" class="upc.yqs.Student" scope="singleton">
    <property name="name" value="yqs"></property>
    <property name="age" value="18"></property>
</bean>

我将这个bean的scope属性设置成了singleton,表示它是一个单例,接下来我们通过测试程序测试一下:

@Test
public void singletonTest() {
    Student stu1 = (Student) context.getBean("student_yqs");
    Student stu2 = (Student) context.getBean("student_yqs");
    System.out.println("stu1的地址:" + System.identityHashCode(stu1) + " stu2的地址:" + System.identityHashCode(stu2));
}

输出:

stu1的地址:757004314 stu2的地址:757004314

我们发现两个对象其中是指向同一个对象,这就是单例模式的作用。
那么如果我们为同一个类定义两个bean,并且都指定为单例,那么会发生什么呢。
我们修改一下xml,增加一个bean,但是指向同一个类,并且都设置为singleton

<bean id="student_yqs" class="upc.yqs.Student" scope="singleton">
    <property name="name" value="yqs"></property>
    <property name="age" value="18"></property>
</bean>
<bean id="student_bbb" class="upc.yqs.Student" scope="singleton">
    <property name="name" value="bbb"></property>
    <property name="age" value="17"></property>
</bean>

接下来我们再写一个测试程序试试:

@Test
public void singletonTest2() {
    Student stu_yqs1 = (Student) context.getBean("student_yqs");
    Student stu_yqs2 = (Student) context.getBean("student_yqs");
    Student stu_bbb1 = (Student) context.getBean("student_bbb");
    Student stu_bbb2 = (Student) context.getBean("student_bbb");
    System.out.println("stu_yqs1的地址:" + System.identityHashCode(stu_yqs1));
    System.out.println("stu_yqs2的地址:" + System.identityHashCode(stu_yqs2));
    System.out.println("stu_bbb1的地址:" + System.identityHashCode(stu_bbb1));
    System.out.println("stu_bbb2的地址:" + System.identityHashCode(stu_bbb2));
}

输出:

stu_yqs1的地址:757004314
stu_yqs2的地址:757004314
stu_bbb1的地址:996796369
stu_bbb2的地址:996796369

会发现两个id得到的对象其实不是同一个,但是同一个id不管获取几次都是同一个id。也就是说bean里面的单例不是传统意义上的单例,传统意义的单例是针对一个class来讲的,而是针对一个bean来讲是一个单例。

多例的话同理,我们将scope属性设置成prototype即可(注意默认值是singleton)。这样子我们每次get到的bean都将会是不同的对象。有了上面的基础,这点比较容易理解,就不具体演示了。

带构造函数的bean的定义

如果我们想要利用构造函数来初始化我们的bean,那么就可以使用<constructor-arg>标签来对构造函数的参数进行传值。
比如我的学生类有这么一个构造函数:

public Student(String name, int age) {
    this.name = name;
    this.age = age;
}

那么想要使用这个构造函数,我们只需要这样子定义:

<bean id="student_asd" class="upc.yqs.Student" scope="singleton">
    <constructor-arg name="name" value="asd"/>
    <constructor-arg name="age" value="5"/>
</bean>

注意,我们定义的时候必须要和这个类中的某个构造函数匹配上才可以,否则会报错,就比如我把上面xml里面第二个constructor-arg给它删除了,那就会报错,因为Student类里面不存在只有一个age的构造函数。

如果有两个构造函数的参数数量一致,那么为了避免歧义,我们可以显式的指明参数类型:

<bean id="student_asd" class="upc.yqs.Student" scope="singleton">
    <constructor-arg type="java.lang.String" name="name" value="asd"/>
    <constructor-arg type="java.lang.Integer" name="age" value="5"/>
</bean>

参数特殊类型的构造函数的bean定义

上面讲到的其实都是一些简单的数据,如果遇到自定义类作为参数,或者List,Map作为参数,那么就需要一些特殊的语法来帮助我们实现。
1、自定义类作为参数
假设Student类有这么一个构造函数:

 public Student()
 {
     this.name="null";
     this.age=-1;
 }

 public Student(Student npy)
 {
     this();
     this.npy=npy;
 }

我们传入一个学生类对象作为参数,npy就是表示这个学生的男/女朋友(我实在想不出学生还有什么其它的一对一关系了,难道是父子??)
那么我们在定义bean的时候就可以利用ref属性(代替value)来传入一个Student对象:

<bean id="student_yqs" class="upc.yqs.Student" scope="prototype">
    <property name="name" value="yqs"></property>
    <property name="age" value="18"></property>
</bean>
<bean id="student_yyy" class="upc.yqs.Student">
    <constructor-arg type="upc.yqs.Student" name="npy" ref="student_yqs"/>
</bean>

ref里面写的就是beanID,这里这么写的话就表示yyy的npy是yqs了。
我们写个测试程序试试看:

@Test
public void constructorTest2()
{
    Student stu_yyy=(Student) context.getBean("student_yyy");
    System.out.println(stu_yyy.npy);
}

输出:

Student{name='yqs', age=18}

符合我们的预期

2、List作为参数
比如Student有这么一个构造函数:

public Student(List<Student> friends)
{
    this.friends = friends;
}

那么我们定义时就可以这么做:

<bean id="student_yyq" class="upc.yqs.Student">
    <constructor-arg type="java.util.List" name="friends">
        <list>
            <ref bean="student_yqs"></ref>
            <ref bean="student_yyy"></ref>
            <ref bean="student_asd"></ref>
        </list>
    </constructor-arg>
</bean>

写一个测试程序:

@Test
public void constructorTest3()
{
    Student stu_yyq=(Student) context.getBean("student_yyq");
    System.out.println(stu_yyq.friends);
}

输出:

[Student{name='yqs', age=18}, Student{name='null', age=-1}, Student{name='asd', age=5}]

也是没什么问题。

3、map、set作为参数
道理比较相似,不具体讲了:

<bean id="student_msq" class="upc.yqs.Student">
    <constructor-arg type="java.util.Map" name="map">
        <map>
            <entry key="111" value="5"></entry>
            <entry key="222" value="6"></entry>
            <entry key="333" value="7"></entry>
            <entry key="444" value="8"></entry>
        </map>
    </constructor-arg>
    <constructor-arg type="java.util.Set" name="set">
        <set>
            <value>9</value>
            <value>10</value>
            <value>11</value>
        </set>
    </constructor-arg>
</bean>

懒加载

在定义bean时如果我们将其lazy_init属性设为true(只有当scope="singleton"时这个属性才会生效),那么这个bean就会变成懒加载,也就是当我们使用getBean(或者其它bean中用ref引用了这个bean)时,这个bean才会被加载。设置为false(默认也为false)的话,程序一运行就会被加载。

init-method:容器加载 Bean 时调用该方法,类似于 Servlet 中的 init() 方法(scope=singleton时只会调用一次,scope=prototype时每次getBean都会调用)
destroy-method:容器删除 Bean 时调用该方法,类似于 Servlet 中的 destroy() 方法。该方法只在 scope=singleton 时有效

参数的值填的是该bean指向的类的成员方法的名字(可以是静态类)
偷个懒,不贴代码了,大家自己试试。

标签:java,单例,spring,System,stu,bean,Student,构造函数
来源: https://blog.csdn.net/qq_31618549/article/details/121988259

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有