【Spring入门系列】篇3:再探IOC
前言
在上一篇SpringIOC入门中我们介绍了SpringIOC的基本使用,现在我们更加深入的学习一下SpringIOC。
一、Bean的相关配置
在前文我们简单了解了bean的使用,下面我们再来具体介绍一下bean。
1.名称与标识
- id: 使用了约束中的唯一约束。里面不能出现特殊字符的
- name: 没有使用约束中的唯一约束。里面可以出现特殊字符。
id我们前文有提到过,就是指定我们需要管理的类方便我们进行获取对象。name作用也是一样,只不过id具有唯一性,name不具有唯一性。我们一般都是使用id不会去使用name。
2.设置对象的生命周期
我们还可以通过bean属性来设置对象的生命周期主要有以下两个属性:
- init-method:Bean被初始化的时候执行的方法
- destroy-method:Bean被销毁的时候执行的方法(Bean是单例创建,工厂关闭)
在前文我们说过对象是在ApplicationContext创建时就创建好了,所以init-method会在ApplicationContext创建完就执行,当ApplicationContext工厂关闭时就会执行destroy-method(手动关闭)。接下来我们举个例子:
首先创建一个Person类,并将Person类交由Spring管理:
public class Person {
public void init() {
System.out.println("person---init");
}
public void destroy() {
System.out.println("person---destroy");
}
}
<?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="person" class="icu.thinmoon.demo2.Person" init-method="init" destroy-method="destroy"></bean>
</beans>
接着编写测试类运行一下看看结果:
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class PersonTest {
@Test
public void test() {
ApplicationContext applicationContext
= new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println("--------------");
}
}
运行结果:
person---init
--------------
可以看到,在applicationContext初始化完成便调用了person类的init方法。当我们手动关闭工厂的时候,工厂内的所有对象都会被销毁可以看如下代码:
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class PersonTest {
@Test
public void test() {
ClassPathXmlApplicationContext applicationContext
= new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println("--------------");
applicationContext.close();
}
}
运行结果:
person---init
--------------
person---destroy
需要注意的是:
ClassPathXmlApplicationContext applicationContext
= new ClassPathXmlApplicationContext("applicationContext.xml");
我们在这使用的是ClassPathXmlApplicationContext 子类,父类接口没有close方法。
3.Bean的作用范围scope
我们可以通过配置scope属性来配置bean的作用范围,其具体的值有以下几种:
值 | 意义 |
---|---|
singleton | 默认采用此方式,Spring会采用单例模式创建这个对象。工厂关闭自动销毁 |
prototype | 多例模式。工厂关闭对象不会自动销毁,依旧需要垃圾回收 |
request | 应用在web项目中,Spring创建这个类以后,将这个对象存入到request范围中。 |
session | 应用在web项目中,Spring创建这个类以后,将这个对象存入到session范围中 |
globalsession | 应用在web项目中,必须在porlet(基于Java的Web组件,子域名)环境下使用。但是如果没有这种环境,相对于session。 |
我们需要重点关注spring默认是采用单例的方式创建对象,若需改成多例我们需要将scope配置成prototype
4.工厂实例化的方式
工厂实例化的方式是指Spring在帮我们生成对象时我们可以指定Spring如何去生成对象,主要有以下三种实现方法:
-
无参构造:这是默认方法,即Spring调用该类的默认无参构造函数去帮我们创建对象
-
静态工厂实例化:我们可以利用factory-method属性指定一个静态方法帮助我们生产对象
public class User { public static User create() { System.out.println("----create user----"); return new User(); } }
<bean id="user" class="icu.thinmoon.demo3.User" factory-method="create"></bean>
-
实例工厂实例化:实例工厂实例化是指在利用已有的bean来创建对象
<bean id="user" class="icu.thinmoon.demo3.User" factory-method="create"></bean> <bean id="user2" class="icu.thinmoon.demo3.User" factory-bean="user"></bean>
综上,我们可以通过上述3种方式来设置Spring实例化的方式,在实际使用中一般使用第一种方式比较多。
二、再探属性注入
上一篇文章中我们提到了set方法属性注入方式,其实属性注入方式还有很多种我们来挨个学习一下:
1.set方法属性注入
前文有提到set方法属性注入,在这我们加上引用类型属性注入方式:
Student:
public class Student {
String name;
Integer id;
Dog dog;
public void setName(String name) {
this.name = name;
}
public void setId(Integer id) {
this.id = id;
}
public void setDog(Dog dog) {
this.dog = dog;
}
}
Dog:
public class Dog {
String name;
public void setName(String name) {
this.name = name;
}
}
配置applicationContext.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="dog" class="icu.thinmoon.demo4.Dog">
<property name="name" value="旺财"/>
</bean>
<bean id="student" class="icu.thinmoon.demo4.Student">
<property name="name" value="小明"/>
<property name="id" value="001"/>
<property name="dog" ref="dog"/>
</bean>
</beans>
使用测试类测试一下:
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class StudentTest {
@Test
public void test() {
ApplicationContext applicationContext
= new ClassPathXmlApplicationContext("applicationContext.xml");
Student student = (Student) applicationContext.getBean("student");
System.out.println(student.id);
System.out.println(student.name);
}
}
测试结果:
1
小明
可以看到,引用类型的属性注入方式与基本类型相似,只不过我们在这使用的是ref属性,表示的是应用工厂内的某个bean,所以我们需要将引用的对象也加入工厂。
<property name="dog" ref="dog"/>
2.构造方法属性注入
使用构造方法属性注入肯定需要我们提供构造方法,使用constructor-arg便能完成,修改上面代码如下:
Student:
public class Student {
String name;
Integer id;
Dog dog;
public Student(String name, Integer id, Dog dog) {
this.name = name;
this.id = id;
this.dog = dog;
}
}
applicationContext.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="dog" class="icu.thinmoon.demo4.Dog">
<property name="name" value="旺财"/>
</bean>
<bean id="student" class="icu.thinmoon.demo4.Student">
<constructor-arg name="name" value="小明"/>
<constructor-arg name="id" value="001"/>
<constructor-arg name="dog" ref="dog"/>
</bean>
</beans>
测试类及测试结果同上。
3.p名称空间属性注入
p名称空间属性注入其实就是set方法属性注入的一种简化写法,使用p名称空间属性注入我们首先要在配置文件中加上下面这条代码:
xmlns:p="http://www.springframework.org/schema/p"
使用p名称空间后的配置文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="dog" class="icu.thinmoon.demo4.Dog" p:name="旺财"/>
<bean id="student" class="icu.thinmoon.demo4.Student" p:name="小明" p:id="001" p:dog-ref="dog"/>
</beans>
以上配置文件和set属性注入执行效果完全一致。
4.spEL表达式属性注入
spEL表达式也是一种简写方式,我们可以通过spEL表达式直接引用对象甚至对象的属性,比如说:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="dog" class="icu.thinmoon.demo4.Dog">
<property name="name" value="旺财"/>
</bean>
<bean id="student" class="icu.thinmoon.demo4.Student">
<property name="name" value="#{‘小明’}"/>
<property name="id" value="#{1}"/>
<property name="dog" value="#{dog}"/>
</bean>
</beans>
我们可以通过#{}的形式进行注入,字符串需要加上单引号。我们还可以在括号内调用对象属性、方法等,类似这样:
<property name="name" value="#{dog.name}"/>
这种方式开发过程一般不使用,了解即可。
5.集合属性注入
修改Student如下:
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Student {
String[] array;
List<String> list;
Set<String> set;
Map<Integer, String> map;
public void setArray(String[] array) {
this.array = array;
}
public void setList(List<String> list) {
this.list = list;
}
public void setSet(Set<String> set) {
this.set = set;
}
public void setMap(Map<Integer, String> map) {
this.map = map;
}
}
applicationContext.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"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="student" class="icu.thinmoon.demo4.Student">
<!--数组注入-->
<property name="array">
<list>
<value>小明</value>
<value>小红</value>
<value>小红</value>
<value>小红</value>
</list>
</property>
<!--List注入-->
<property name="list">
<list>
<value>小明</value>
<value>小红</value>
<value>小红</value>
<value>小红</value>
</list>
</property>
<!--set注入-->
<property name="set">
<set>
<value>小明</value>
<value>小红</value>
<value>小红</value>
<value>小红</value>
</set>
</property>
<!--map-->
<property name="map">
<map>
<entry key="001" value="abc"/>
<entry key="002" value="def"/>
<entry key="003" value="ghj"/>
</map>
</property>
</bean>
</beans>
附录:分模块配置
我们在开发中每个人都可以写一个自己的配置文件,然后在主配置文件中进行引入即可:
applicationContext.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">
<!--id: 为自己取得名称 class:具体实现类的全路径-->
<bean id="userDao" class="icu.thinmoon.demo1.UserDaoMysqlImpl">
<!--
name: 属性名称
value: 属性的值
注意:需要提供set方法
-->
<property name="name" value="thinmoon"/>
</bean>
<!--导入另外的配置文件-->
<import resource="applicationContext2.xml"/>
</beans>
applicationContext2.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="user" class="icu.thinmoon.demo3.User" factory-method="create"></bean>
<bean id="user2" class="icu.thinmoon.demo3.User" factory-bean="user"></bean>
</beans>