Spring(二)Spring的使用

上一篇文章,使用Spring完成了将一个对象放入容器中,以及可以为这个对象的属性赋值,但是还有一些具体的细节和Spring的其它内容放在本篇文章中。

1.对象何时创建?

我们知道,对象的创建都是通过构造函数的,虽然交给了Spring容器来帮我们创建,但是本质是不变的。

我们在Person类中加一个无参构造函数:

public Person() {
    System.out.println("person对象创建了......");
}

然后只测试:

@Test
public void test01(){
    ApplicationContext application = new ClassPathXmlApplicationContext("applicationContext.xml");
    //        Person person = (Person) application.getBean("person");
    //        System.out.println(person);
}

查看控制台:

person对象创建了......

可以得出结论:对象在初始化容器时就已经创建了。

(当然,还想要了解具体是怎么创建的,就要去看源码了)

2.创建的对象是单实例还是多实例?

测试:

@Test
public void test01(){
    ApplicationContext application = new ClassPathXmlApplicationContext("applicationContext.xml");
    Person person = (Person) application.getBean("person");
    Person person2 = (Person) application.getBean("person");
    System.out.println(person == person2);
}

结果:

person对象创建了......
true

可以得出结论:默认情况下,Spring容器创建的对象是单实例的。

如果我们在配置文件中配置多个呢?

<bean id="person" class="com.dh.pojos.Person">
    <property name="name" value="zhangsan"/>
    <property name="age" value="18"/>
    <property name="sex" value="男"/>
</bean>

<bean id="person2" class="com.dh.pojos.Person">
    <property name="name" value="lisi"/>
    <property name="age" value="22"/>
    <property name="sex" value="男"/>
</bean>

测试:

@Test
public void test01(){
    ApplicationContext application = new ClassPathXmlApplicationContext("applicationContext.xml");
    Person person = (Person) application.getBean("person");
    Person person2 = (Person) application.getBean("person2");
    System.out.println(person == person2);
}

结果:

person对象创建了......
person对象创建了......
false

可以得出结论:在配置文件中,配置了几个bean,Spring容器就会创建几个bean,但是每一个bean的创建方式都是单实例。

3.作用域

那如果我们想要每次获取的bean都是不一样的,即bean为多实例的,Spring容器也是可以做到的。

只需要在配置文件中添加一个作用域,将作用域设置为多实例即可:

<bean id="person" class="com.dh.pojos.Person" scope="prototype">
    <property name="name" value="zhangsan"/>
    <property name="age" value="18"/>
    <property name="sex" value="男"/>
</bean>

(Spring默认的作用域为singleton,可以不写)

测试:

@Test
public void test01(){
    ApplicationContext application = new ClassPathXmlApplicationContext("applicationContext.xml");
    Person person = (Person) application.getBean("person");
    Person person2 = (Person) application.getBean("person");
    System.out.println(person == person2);
}

结果:

person对象创建了......
person对象创建了......
person对象创建了......
false

调用三次构造函数的原因是,person1为多实例,创建了两个,而配置文件中也还有person2,所以又调了一次。

(除这两个之外,作用域还有request、session、application这三个与JavaWeb有关的。)

4.如何给属性赋值

Spring利用DI为属性赋值,上篇文章中,我们介绍了使用Property标签给bean的属性赋值,那么原理是什么呢?

Propety标签为对象的属性赋值,实际上是利用了类的setter/getter方法.

为属性赋值还有一种办法,就是通过有参构造方法:

public Person(String name, int age, char sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;
    System.out.println("Person类的有参构造......");
}
<bean id="person3" class="com.dh.pojos.Person" scope="prototype">
    <constructor-arg name="name" value="wangwu"/>
    <constructor-arg name="age" value="20"/>
    <constructor-arg name="sex" value="女"/>
</bean>

测试:

@Test
public void test01(){
    ApplicationContext application = new ClassPathXmlApplicationContext("applicationContext.xml");
    Person person = (Person) application.getBean("person3");
    System.out.println(person);
}

结果:

Person类的有参构造......
Person{name='wangwu', age=20, sex=女}

需要注意的是:

使用构造方法给属性赋值,在赋值时,必须为构造方法中的所有属性赋值,否则xml文件中会报错。

但是使用setter/getter方法为属性赋值,就可以随意参数。

abstract

当bean中设置abstract为true时,代表该bean只是用来被继承的,不能实例化bean。

parent

可以为一个类指定一个parent,那么就可以继承那个bean的属性了。

5.c命名空间和p命名空间

可以引入c命名空间和p命名空间:用来简化对属性赋值的书写。

首先,要引入名称空间:

xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"

然后,使用:

<bean id="person4" class="com.dh.pojos.Person" p:name="zaoliu" p:age="19" p:sex="男"/>
<bean id="person5" class="com.dh.pojos.Person" c:name="qianqi" c:age="30" c:sex="男"/>
<!--    使用c命名空间,还可以使用构造方法中对应的参数序号,顺序一定要匹配上-->
<bean id="person6" class="com.dh.pojos.Person" c:_0="qianqi" c:_1="30" c:_2="男"/>

6.实例化bean的三种方法

(1)通过无参构造

之前所提及的方式就是通过无参构造,然后利用反射,通过类的全称限定名来创建对象的。

一定要存在无参构造方法!

<bean id="person" class="com.dh.pojos.Person"/>

(2)使用静态工厂

首先书写一个类,里面包含一个静态方法:

package com.dh.factory;

import com.dh.pojos.Person;

public class MyFactory {
    
    public static Person getPerson(){
        return new Person();
    }
}

使用:

我们知道静态方法是可以直接通过类名调用的,所以,我们需要知道类,和类中的静态方法即可。

<bean id="person" class="com.dh.factory.MyFactory" factory-method="getPerson"/>

(3)使用实例工厂

我们在工厂类中再添加一个方法:

package com.dh.factory;

import com.dh.pojos.Person;

public class MyFactory {

    //静态方法
    public static Person getPerson(){
        return new Person();
    }
    
    //非静态方法
    public Person getPerson2(){
        return new Person();
    }
}

使用:

调用一个非静态方法时,首先要获得该类的对象,再通过该对象去调用方法:

<bean id="factory" class="com.dh.factory.MyFactory"/>
<bean id="person" factory-bean="factory" factory-method="getPerson2"/>

7.获得bean的四种方法

(1)使用id(或者name)

除了id也可以使用name属性标识一个bean,name属性没有那么严格,一般使用id,所以在此不做介绍。

需要强制类型转换。

Person person = (Person) application.getBean("person");

(2)根据类名.class

不再需要强制类型转换。

Person person = application.getBean(Person.class);

(3)根据类名

当没有配置id时,可以直接通过类名来获取bean

<bean class="com.dh.factory.MyFactory"/>
Person person = (Person) application.getBean("com.dh.pojos.Person");

当配置了多个bean,为同一个类,但是都没有指定id时,可以使用类名+#序号(从0开始)

Person person = (Person) application.getBean("com.dh.pojos.Person#1");//会获取配置文件中的第二个

(3)根据接口名

我们先来写一个接口:

package com.dh.service;

public interface UserService {
}

然后为该接口书写两个实现类:

package com.dh.service;

public class UserServieImpl1 implements UserService{
}
package com.dh.service;

public class UserServieImpl2 implements UserService{
}

在xml中配置:

<bean class="com.dh.service.UserServieImpl1"/>
<bean class="com.dh.service.UserServieImpl2"/>

然后使用接口获取bean:

UserService userService = application.getBean(UserService.class);

此时肯定是会报错的,因为UserService有两个实现类,Spring根本不知道你需要的是哪一个。

8.bean的生命周期

在配置bean的时候,有两个参数:

init-method="" destroy-method=""

可以自己书写初始化方法和销毁方法。

需要注意的是:销毁方法只在单实例创建对象时有效。

9.SpEL注入

SpEL,是Spring expression language的缩写,在为对象的属性赋值时,可以使用#{表达式}。

表达式中可以为:数学运算符、关系运算符、逻辑运算符、条件运算符,集合和正则表达式。

10.其它类型的注入(实体类,容器)

如果一个bean中的属性包含了复杂的数据类型,如其它的类,或者是Map、List、Set、Properties,又该如何赋值呢?

在Person类中添加一些属性及其setter/getter方法:

<bean id="computer" class="com.dh.pojos.Computer">
        <property name="brand" value="Dell"/>
        <property name="price" value="4000"/>
    </bean>

    <bean id="person" class="com.dh.pojos.Person">
        <property name="name" value="Tom"/>
        <property name="age" value="22"/>
        <property name="sex" value="男"/>
        
        <!--     ref为引用其它的bean-->
        <property name="computer" ref="computer"/>
        
        <property name="map">
            <map>
                <entry key="k1" value="v1"/>
                <entry key="k2" value="v2"/>
            </map>
        </property>
        
        <property name="set">
            <set>
                <value>set1</value>
                <value>set2</value>
            </set>
        </property>
        
        <property name="list">
            <list>
                <value>list1</value>
                <value>list2</value>
            </list>
        </property>
        
        <property name="properties">
            <props>
                <prop key="p1">v1</prop>
                <prop key="p2">v2</prop>
            </props>
        </property>
    </bean>

结果:

Person{name='Tom', age=22, sex=男, computer=Computer{brand='Dell', price=4000.0}, map={k1=v1, k2=v2}, list=[list1, list2], set=[set1, set2], properties={p2=v2, p1=v1}}
posted @ 2021-04-01 10:36  deng-hui  阅读(116)  评论(0编辑  收藏  举报