SpringIOC
IOC(Inversion of Control) ,所谓控制反转就是应用本身不负责依赖对象的创建及维护,依赖对象的创建及维护是由外部容器(比如SpringIOC容器)负责的。这样控制权就由应用转移到了外部容器,控制权的转移就是所谓的反转。在传统编程中,当我们创建一个对象时,需要在程序显示的new一个,这时对象的创建及维护的控制权在我们自己手中,而在Spring框架中,则不需要我们手动new,这时对对象的控制权转移到了SpringIOC容器中,当我们需要对象时,直接从容器中获取即可,至于对象怎么来的,我们无需关心,因为SpringIOC容器为我们做了这些事,就像我们洗衣服时,我们需要自己做抹肥皂,搓衣服、漂洗及拧干等动作,而当洗衣机出现之后,这些工作全部交由洗衣机这个容器来做,我们只需插上电源,按下启动开关即可,至于洗衣服是如何以及何时放洗衣粉,洗衣服、漂洗、脱水,我们不需要知道,我们只关心,当洗衣机停止工作后,就表示我们的衣服已经洗干净了,SpringIOC容器就相当于这个洗衣机一样,只不过洗衣机装的是衣服,而容器装的是对象,在Spring中把这一个一个的对象称为bean,那么这些bean放在什么地方呢?答案是配置文件中,当我们的容器启动之后,首先会读取配置文件中各个bean,并对其进行实例化,配置等,配置文件格式像下面这样,我们称这种实例化bean的方式为类构造器实例化bean,通常我们需要被实例化的bean提供一个默认的构造器。
<?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-2.5.xsd">
<bean id="..." class="...">
<!-- collaborators and configuration for this bean go here -->
</bean>
<bean id="..." class="...">
<!-- collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions go here -->
</beans>
可以看出SpringIOC容器可以包含一个或多个bean,每个bean都有一个或多个id。这些id在当前IoC容器中必须唯一。如果一个bean有多个id,那么其他的id在本质上将被认为是别名。当基于这种配置文件的方式来配置bean时,将通过id或name属性来指定bean标识符。不过为一个bean提供一个name并不是必须的,如果没有指定,那么容器将为其生成一个惟一的name。bean的class需要填写完整类名,即包名+类名的格式。bean的命名采用标准的Java命名约定,即小写字母开头,首字母大写间隔的命名方式。如accountManager、 accountService 、userDao及loginController,等等。假设现在我们已经配置好了bean,那么该如何获取这些已经定义好的bean呢,前面讲过这些bean都放在了SpringIOC容器,这时我们就需要实例化容器(实例化容器的过程也即启动容器的过程),就像我们的洗衣机一样,如果我们只把衣服放进洗衣机而没有接通电源按下启动开关洗衣机是不会帮我们洗的,实例化容器的过程非常简单,可以看到,ClassPathXmlApplicationContext 传递的是一个数组,我们可以同时启动多个容器。
ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[]{"beans.xml"});
采用这种方式实例化容器,需要将spring的配置文件放到当前项目的classpath路径下,classpath路径指的是当前项目的src目录,该目录是java源文件的存放位置。除了这种方式,我们也可以在文件系统路径下寻找配置文件来实例化容器
ApplicationContext ctx = new FileSystemXmlApplicationContext(new String[]{“d:\\beans.xml“});
同样Spring的配置文件也可以指定多个,可以通过String数组传入。我们通常使用的是第一种方式来启动容器。很多时候,由于Spring需要管理和配置的东西比较多,如果都放在一个配置文件中,配置文件会变的比较大,同时不方便与维护,一般好的做法是按照功能模块将Spring配置文件分开,例如:DAO层配置到一个spring-dao.xml配置文件中,Service层配置到spring-service.xml文件中,Struts的action配置到spring-action.xml文件中,然后通过下面的办法将这些分散的配置文件组合起来:
在一个作为Spring总配置文件中的<bean>元素定义之前,通过<import>元素将要引入的spring其他配置文件引入,例如:
<beans>
<import resource=”spring-dao.xml”/>
<import resource=”spring-service.xml”/>
<import resource=”spring-action.xml”/>
……
<bean>
</bean>
……
</beans>
这样我们只需引入一个配置文件即可,启动了容器之后,我们就可以在代码中获取我们所需的bean了,获取bean的方式同样也很简单,像下面这样
ctx.getBean("bean");
这里的bean指的是配置文件中bean的id值,这时我们就可以调用这个类来为我们工作了。在SpringIOC容器还可以为bean设置别名,就像我们除了有一个身份证上面的名字之外,通常还会有一个小名,像下面这样为bean配置一个别名toName,这时就可以用toName来引用id名为fromName的bean。
<bean id="fromName" class="...">
<alias name="fromName" alias="toName"/>
则下面的两行代码的效果是一样的
ctx.getBean("fromName");
ctx.getBean("toName");
通过一个简单的例子感受一下SpringIOC功能,首先我们有一个bean
public class Person {
public void say() {
System.out.println("Hello Spring");
}
}
接下来编写Spring的配置文件,通过<bean />标签来让SpringIOC容器来管理我们定义的Person bean<?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-2.5.xsd">
<bean id="person" class="org.spring.Person">
</bean>
</beans>
public class IOCTest {
@Test
public void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person = (Person) context.getBean("person");
person.say();
}
}
实例化Bean的方式
1、使用类构造器实例化
<bean id="person" class="org.spring.Person">
2、使用静态工厂方法实例化
public class Student {
}
public class StudentStaticFactory {
public static Student createStudentBean() {
return new Student();
}
}
<bean id="student" class="org.spring.initbean.StudentStaticFactory" factory-method="createStudentBean" />
3、使用实例工厂方法实例化
public class Student {
}
public class StudentInstanceFactory {
public Student createStudentBean() {
return new Student();
}
}
<bean id="studentInstanceFactory" class="org.spring.initbean.StudentInstanceFactory" />
<bean id="student" factory-bean="studentInstanceFactory" factory-method="createStudentBean" />
<bean id="person" class="org.spring.Person" lazy-init="true" />
<beans default-lazy-init="true" ...>
public class Person {
public Person() {
System.out.println("构造器");
}
public void say() {
System.out.println("Hello Spring");
}
}
测试代码public class IOCTest {
@Test
public void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
}
}
这段代码表示初始化Spring容器,也即启动容器,执行代码之后控制台并没有打印任何信息,而当代码修改如下时public class IOCTest {
@Test
public void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person = (Person) context.getBean("person");
}
}
控制打印出构造器字符串,可知为bean设置了延迟加载之后,只有在第一次获取bean时,容器才帮我们实例化bean,延迟加载的缺陷是在spring容器启动的时候,我们无法检验出错误。Bean的作用域
singleton作用域:
prototype作用域:
<bean id="person" class="org.spring.Person" scope="singleton"/>
public class IOCTest {
@Test
public void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person = (Person) context.getBean("person");
Person person2 = (Person) context.getBean("person");
// person.say();
System.out.println(person == person2);
}
}
public class Person {
public Person() {
System.out.println("构造器");
}
public void say() {
System.out.println("Hello Spring");
}
}
<bean id="person" class="org.spring.Person" scope="prototype"/>
init方法与destroy方法
public class Person {
public Person() {
System.out.println("构造器");
}
/*public void say() {
System.out.println("Hello Spring");
}*/
public void init() {
System.out.println("washing......");
}
public void eat() {
System.out.println("eatting......");
}
public void destroy() {
System.out.println("wape mouth.....");
}
}
在配置文件中指定init-method与destroy-method,如
<bean id="person" class="org.spring.Person" init-method="init" destroy-method="destroy" scope="singleton"/>
public class IOCTest {
@Test
public void test() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person = (Person) context.getBean("person");
person.eat();
context.destroy();
}
}