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}}