2.XML管理对象(Bean)
在我们Spring管理的时候,说起对象,都是一个个的JavaBean。JavaBean并不是一项特殊的技术,它就是对于Java的可重用的对象的一些编码的要求。如属性私有,构造方法,getter和setter方法等。而Spring IoC容器中,管理的就是这一个个的JavaBean。所以我以后就用Bean来指代容器中的对象。
spring对于Bean的管理,包含了3种配置方式。
第一种是基于XML配置Bean、第二种是基于注解配置Bean、第三种是基于Java代码配置Bean。
这三种配置bean的方式的本质都是一样的,都是告诉Spring IoC 容器如何实例化和管理这些Bean。只是他们的表现形式不一样而已。
下面就来讲解基于XML来管理对象。还是回到上面的例子。
applicationContext.xml这个文件名是约定俗称的,一般都叫这个名字。在配置文件中,所有的对象都统一使用Bean这个标签。里面的id属性指的是指定的类被IoC容器实例化后,对象的(唯一标识)名字是什么,这里我们叫它sweetApple ,class指定要被IoC容器实例化的那个类。至于<bean>标签里面的<property>并不是必须的。在后面讲解属性注入的时候再详细解释。
spring提供了ApplicationContext来创建IoC容器。ApplicationContext是一个接口,有很多具体的实现类,其中ClassPathXmlApplicationContext这个类就实现了从当前类路径去读取指定的xml文件并解析加载的过程。ClassPathXmlApplicationContext是最常用的核心类之一。当运行了这一段代码,就意味着在我们Java的运行内存中保存了IoC容器,并且IoC容器根据刚才的配置,创建了对应的对象,并对这些对象进行管理。
ClassPathXmlApplicationContext允许加载多个xml文件的,采用传入字符串数组的形式。
String[] configLocations=new String[]{"classpath:applicationContext.xml","classpath:applicationContext-1.xml"}; ApplicationContext context=new ClassPathXmlApplicationContext(configLocations);
3.三种XML实例化Bean的配置方式:
1.基于默认无参构造方法实例化对象
2.基于静态工厂实例化对象
3.基于工厂实例方法来实例化对象
基于默认无参构造方法实例化对象
创建一个名为s02的空的Maven项目,引入依赖spring-context。和之前一样创建entity包,里面创建苹果类Apple和孩子类Child类。
然后编写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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <!--bean标签默认通过类的默认无参构造方法创建对象--> <bean id="apple1" class="com.haiexijun.entity.Apple"> </bean> </beans>
在里面配置了一个Apple的对象,名字为apple1。
然后在Apple类的无参默认的构造方法里面添加一行代码:
public Apple() { System.out.println("Apple对象已创建,"+this); }
在有main方法的java类里编写如下代码运行,会发现Apple的默认无参构造方法
package com.haiexijun.app; import com.haiexijun.entity.Apple; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringApplication { public static void main(String[] args) { ApplicationContext context=new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); } }
运行结果:
那如果要用带参数的构造方法来创建对象该怎么做,下一节在进行详解。
利用带参构造方法实例化对象
在bean下面插入一个<constructor-arg>的子标签,在这子标签中,我们可以通过设置name属性来为带参构造方法的指定参数,用value属性来设置对应的值。
除了可以用name属性来指定构造方法的参数外,还可以用index属性来设置指定的参数,用value属性来设置值。index说明参数的前后位置。index从0开始。
实际工作中,更推荐第一种方式来传参。这里就不作演示了。但有参构造方法有多个时,比如一个类有一个3个参数的构造方法,有一个4个参数的构造方法。我们在bean中传入几个参数,程序就调用对应数量参数的构造方法。
基于静态工厂实例化对象
其实这种实例化对象的方式用的不多,主要还是构造方法来实例化对象。我们通常说的工厂,其实指的是工厂模式。作为工厂模式,他的根本用途就是隐藏创建类的细节。通过一个额外的工厂类来组织创建我们需要的对象。按照工厂的表现形式,又可以分为静态工厂和工厂实例。
我们通过代码案例来了解和体验基于静态工厂实例化对象。
创建一个factory子包,保存工厂类。然后创建一个java类AppleStaticFactory。里面有一个方法,用于创建甜苹果。
package com.haiexijun.factory; import com.haiexijun.entity.Apple; public class AppleStaticFactory { public static Apple createSweetApple(){ Apple apple=new Apple(); apple.setTitle("红富士"); apple.setOrigin("欧洲"); apple.setColor("红色"); return apple; } }
然后在applicationContext.xml中调用这个工厂创建对象。
<!--利用静态工厂获取对象--> <bean id="apple4" class="com.haiexijun.factory.AppleStaticFactory" factory-method="createSweetApple"/>
这里你可能会问了,这种方式创建对象不久和以前传统new创建对象一样吗?其实是有很大的不同的,工厂的职责就是通过静态方法来创建对象,隐藏创建对象的细节。里面如何创建对象,对于我们来说是不可见的。创建者只需要知道但调用了工厂类的createSweetApple后,会创建一个甜苹果就行了。
基于工厂实例方法来实例化对象
工厂实例方法创建对象是指IoC容器对工厂类进行实例化并调用对应的工厂实例方法创建对象的过程。
在factory包下创建一个java类AppleFactoryInstance , 里面的方法没有static关键字。
package com.haiexijun.factory; import com.haiexijun.entity.Apple; /** * 工厂实例方法创建对象是指IoC容器对工厂类进行实例化并调用对应的工厂实例方法创建对象的过程。 */ public class AppleFactoryInstance { public Apple createSweetApple(){ Apple apple=new Apple(); apple.setTitle("红富士"); apple.setOrigin("欧洲"); apple.setColor("红色"); return apple; } }
在applicationContext.xml中调用这个工厂创建对象,这里要创建2个bean。
<!--利用工厂实例方法获取对象--> <bean id="factoryInstance" class="com.haiexijun.factory.AppleFactoryInstance"/> <bean id="apple5" factory-bean="factoryInstance" factory-method="createSweetApple"/>
有一说一,随着spring的功能越来越强大,在实际的使用环境中,基于工厂来创建对象的这种情况越来越少了。我们只做一般性了解就可以了。
<!--利用工厂实例方法获取对象--> <bean id="factoryInstance" class="com.haiexijun.factory.AppleFactoryInstance"/> <bean id="apple5" factory-bean="factoryInstance" factory-method="createSweetApple"/>
4.从IoC容器中获取Bean
xml文件的bean有id和name属性。
id与name属性的相同点有:
bean 中的id与name都是设置对象在IoC容器中的唯一标识。本质上讲是一样的。两者在同一个配置文件中都不允许出现重复。两者允许在多个配置文件中出现重复,新对象覆盖旧对象。
但是他们也有很多不同点:id要求更加严格,一次只能定义一个对象标识。name更为宽松,一次允许定义多个对象标识。我们推荐使用id。
注意:id与name的命名要求要有意义,按驼峰命名书写。
了解:在没有进行设置id和name的情况下
<bean class="com.haiexijun.entity.Apple"> <constructor-arg index="0" value="红富士"/> <constructor-arg index="1" value="红色"/> <constructor-arg index="2" value="欧洲"/> <constructor-arg index="3" value="12.1"/> </bean>
使用全类名来作为bean的标识.
Apple apple3 = context.getBean("com.haiexijun.entity.Apple",Apple.class);
5.路径表达式
作为ClassPathXmlApplicationContext的参数,要求传入一个表达式。这个表达式的含义是去加载我们当前类路径下名为applicationContext的xml文件。
在源代码目录下的resources并不是我们的类路径,而是项目生成的target目录下的classes目录下才是真是的类路径。
ClassPathXmlApplicationContext可以加载多个配置文件,创建一个String数组,按顺序来加载xml配置文件。