Spring IOC—基于XML配置Bean的更多内容和细节(通俗易懂)
目录
一、前言
- 本篇博文是对“Spring IOC——基于XML方式对Bean的配置和管理”一文的内容补充(十、关于Bean配置的更多内容和细节)。
- 注意事项——①代码中的注释也很重要;②不要眼高手低,自己跟着过一遍才有收获;③点击文章的侧边栏目录或者文章开头的目录可以进行跳转。
- 良工不示人以朴,所有文章都会适时补充完善。大家如果有问题都可以在评论区进行交流或者私信up。感谢阅读!
二、Bean配置信息重用
? ? ? ? 1.简介 :?
? ? ? ? 所谓“Bean配置信息重用”,指的是在通过XML配置Bean时,若你想配置一个Bean与之前的某个Bean属性值相同,可以使用 parent="bean_id" 实现,表示当前bean对象的属性值从“id = bean_id”的bean对象中来。
? ? ? ? 2.实例 :?
? ? ? ? ? ? ? ? 首先,我们在beans.xml中配置一个对象,用以充当parent,代码如下 :?
<!-- (1) Bean配置信息重用 -->
<bean class="com.cyan.spring.bean.Student" id="stu10">
<property name="name" value="Cyan"></property>
<property name="age" value="21"></property>
<property name="score" value="455"></property>
</bean>
? ? ? ? ? ? ? ? 然后,另新配置一个Bean,并使用 parent="stu10" 重用上面这个Bean的属性值,代码如下 :
<bean class="com.cyan.spring.bean.Student" id="stu11" parent="stu10"/>
? ? ? ? ? ? ? ? 接着,仍是在测试类StudentBeanByXML中,新定义一个单元测试方法,测试Bean配置信息重用是否成功。
? ? ? ? ? ? ? ? beanConfigReuse()方法代码如下 :?
//(1) 测试 Bean配置信息重用
@Test
public void beanConfigReuse() {
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Student stu10 = ioc.getBean("stu10", Student.class);
Student stu11 = ioc.getBean("stu11", Student.class);
System.out.println("stu10 = " + stu10);
System.out.println("stu11 = " + stu11);
}
? ? ? ? ? ? ? ? 运行结果 :?
? ? ? ? ? ? ? ? 此外,我们还可以直接通过?abstract="true"?定义一个抽象Bean,抽象Bean本身不能被实例化,也就无法获取;但是可以通过parent属性配置一个同抽象类属性值相同的Bean对象,代码如下 :?
<!--配置抽象bean-->
<bean class="com.cyan.spring.bean.Student" id="stu12" abstract="true">
<property name="name" value="Ice"></property>
<property name="age" value="22"></property>
<property name="score" value="462"></property>
</bean>
<bean class="com.cyan.spring.bean.Student" id="stu13" parent="stu12"/>
? ? ? ? ? ? ? ? 在测试类中获取bean并打印bean的信息,代码如下 : (仍在beanConfigReuse()方法中)
//(1) 测试 Bean配置信息重用
@Test
public void beanConfigReuse() {
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Student stu10 = ioc.getBean("stu10", Student.class);
Student stu11 = ioc.getBean("stu11", Student.class);
System.out.println("stu10 = " + stu10);
System.out.println("stu11 = " + stu11);
//-----------------------------------------------------
/*
//Student stu12 = ioc.getBean("stu12", Student.class);
直接使用getBean方法获取抽象Bean会报错————
org.springframework.beans.factory.BeanIsAbstractException:
*/
Student stu13 = ioc.getBean("stu13", Student.class);
//System.out.println("stu12 : " + stu12);
System.out.println("stu13 : " + stu13);
}
? ? ? ? ? ? ? ? 运行结果 :?
三、关于Bean的创建顺序
? ? ? ? 1.简介 :?
? ? ? ? Spring的IOC容器,默认是按照Bean配置时的顺序创建Bean对象。
? ? ? ? 而如果我们在前面配置的Bean对象中用到了 depends-on="bean_id"?即前面配置的Bean对象依赖了后面配置的Bean对象, IOC容器就会先去创建依赖的Bean对象,即使它是在后面配置的。
? ? ? ? 2.实例 :?
? ? ? ? ? ? ? ? 首先,我们来建两个JavaBean类用于演示,在它们的无参构造中打印出提示信息,以便测试。
? ? ? ? ? ? ? ? Commodity类代码如下 :?
package com.cyan.spring.bean;
public class Commodity {
private Integer id;
private String name;
private Double price;
public Commodity() {
System.out.println("Commodity类的无参构造被调用~");
}
public Commodity(Integer id, String name, Double price) {
this.id = id;
this.name = name;
this.price = price;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
@Override
public String toString() {
return "Commodity{" +
"id=" + id +
", name='" + name + '\'' +
", price=" + price +
'}';
}
}
? ? ? ? ? ? ? ? Member类代码如下 :?
package com.cyan.spring.bean;
public class Member {
private Integer id;
private String name;
public Member() {
System.out.println("Member类的无参构造被调用~");
}
public Member(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Member{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
? ? ? ? ? ? ? ? 然后,我们先在beans.xml中按照Member --> Commodity的顺序配置两个Bean对象,即我们认为Member对象应该在Commodity对象之前被创建。代码如下 :?
<!-- (2) Bean创建顺序 -->
<bean class="com.cyan.spring.bean.Member" id="member01">
<property name="id" value="1"></property>
<property name="name" value="Cyan"></property>
</bean>
<bean class="com.cyan.spring.bean.Commodity" id="commodity01">
<property name="id" value="1"></property>
<property name="name" value="Mate90"></property>
<property name="price" value="9999"></property>
</bean>
? ? ? ? ? ? ? ? 接着,在测试类StudentBeanByXML中新定义一个单元测试方法,beanCreateOrder()方法代码如下 :?
//(2) 测试 Bean创建顺序
@Test
public void beanCreateOrder() {
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Member member01 = ioc.getBean("member01", Member.class);
Commodity commodity01 = ioc.getBean("commodity01", Commodity.class);
System.out.println("member01 = " + member01);
System.out.println("commodity01 = " + commodity01);
}
? ? ? ? ? ? ? ? 运行结果 :?
????????????????可以看到,Bean对象的确是依据配置时的顺序被创建的。
????????????????然后,我们利用 depends-on?额外配置两个Bean,要求先配置Commodity对象,且Commodity对象依赖于Member对象,代码如下 : (将刚才配置的两个Bean对象注释掉)
<bean class="com.cyan.spring.bean.Commodity" id="commodity02" depends-on="member02">
<property name="id" value="2"></property>
<property name="name" value="P90"></property>
<property name="price" value="8999"></property>
</bean>
<bean class="com.cyan.spring.bean.Member" id="member02">
<property name="id" value="2"></property>
<property name="name" value="Five"></property>
</bean>
? ? ? ? ? ? ? ? 再次在beanCreateOrder()方法中获取Bean,代码如下 :?
//(2) 测试 Bean创建顺序
@Test
public void beanCreateOrder() {
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Commodity commodity02 = ioc.getBean("commodity02", Commodity.class);
Member member02 = ioc.getBean("member02", Member.class);
System.out.println("commodity02 = " + commodity02);
System.out.println("member02 = " + member02);
}
? ? ? ? ? ? ? ? 运行结果 :?
? ? ? ? ? ? ? ? 可以看到,明明我们在beans.xml中先配置的是Commodity对象,但由于depends-on属性导致Commodity对象依赖于Member对象,因此最终是Member对象首先被创建。
? ? ? ? ? ? ? ? PS:补充一点,对于ref引用——ref属性并不会影响Bean配置的顺序,因为IOC容器对Bean对象的创建是以一个整体来执行的,先完成Bean对象的创建,再进行ref引用的关联。。
四、关于Bean的单例和多例
? ? ? ? 1.简介 :?
? ? ? ? (1) 在Spring的IOC容器中,默认是按照单例形式来创建对象的,即配置一个Bean对象后,IOC容器只会创建一个该Bean的实例,后续使用的是同一个实例。若希望IOC容器按照多例形式来创建Bean对象,可以通过在配置Bean时加入 scope = "prototype"[/?pro?t?ta?p/,原型] 属性来指定。
? ? ? ? (2) 配置的Bean默认scope="singleton"(即使你没有手动写出),若该Bean没有进行任何其他配置,默认会在容器启动时创建该Bean实例,并放入到单例池beanFactory-->singletonObjects中;若配置Bean时指定了scope = "prototype",则Bean实例被创建的时机会被推迟,该Bean只有在getBean(...)时才会被创建。(可通过无参构造打印提示信息进行验证)
? ? ? ? (3) 实际上,Bean实例的创建时机,还取决于Bean的lazy-init (懒加载)属性;默认lazy-init="false",即默认Bean实例都是在容器启动时就创建(以空间换时间)。对于?scope = "prototype"?的情况,不管?lazy-init="true 还是 lazy-init="false",Bean实例都是只有在getBean(...)时才会被创建。而对于?scope="singleton" 的情况,若在单例形式的同时,希望Bean是在getBean(...)被调用时创建,则可以指定懒加载lazy-init="true"。
? ? ? ? 2.实例 :?
? ? ? ? ? ? ? ? 以我们刚才创建的Member类为JavaBean,首先我们注释掉Member类中重写的toString()方法,其目的是可以打印出对象的哈希码值,如下图所示 :?
? ? ? ? ? ? ? ? 然后,我们在beans.xml中配置一个Member对象(将之前配置的Member对象注释掉,防止无参构造打印出的提示信息造成干扰),代码如下 :?
<!-- (3) Bean单例多例 -->
<!-- 即使不手动写出,默认scope = singleton -->
<bean class="com.cyan.spring.bean.Member" id="member03">
<property name="id" value="3"></property>
<property name="name" value="Cyan"></property>
</bean>
? ? ? ? ? ? ? ? 接着,我们在StudentBeanByXML测试类中另定义一个单元测试方法,在测试方法中多次获取 id=member03 的Bean对象,打印对象并比较它们的哈希码值(不同对象的哈希码值一般不同),beanScope()方法代码如下 :?
//(3) 测试 Bean单例多例
@Test
public void beanScope() {
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Member member03 = ioc.getBean("member03", Member.class);
Member member03_EX = ioc.getBean("member03", Member.class);
Member member03_Pro = ioc.getBean("member03", Member.class);
System.out.println("member03 = " + member03);
System.out.println("member03_EX = " + member03_EX);
System.out.println("member03_Pro = " + member03_Pro);
}
? ? ? ? ? ? ? ? 运行结果 :?
? ? ? ? ? ? ? ? 由对象的哈希码值我们可以得知,尽管我们获取了三次Bean对象,打印出的却始终是同一个对象,即是单例的。
? ? ? ? ? ? ? ? 接下来,我们在方才配置的Member对象上添加?scope = "prototype" 属性,如下图所示 :?
? ? ? ? ? ? ? ? 再次运行beanScope()测试方法,结果如下 :?
? ? ? ? ? ? ? ? 可以看到,三次获取到的Bean对象是三个不同的对象,且由Member类无参构造打印出的提示信息我们亦可得知,配置的Member类型的Bean实例被创建了三次。
? ? ? ? ? ? ? ? 注意,假如我们此时将getBean(...)的代码注释掉,如下图所示 :?
? ? ? ? ? ? ? ? 此时,若再次运行beanScope()方法,会发现没有Bean被创建(没有无参构造打印出的提示信息),如下图所示 :?
? ? ? ? ? ? ? ? 原因我们上面也说了——对于?scope = "prototype"(多例形式)?的情况,不管?lazy-init="true 还是 lazy-init="false",Bean实例都是只有在getBean(...)时才会被创建。现在我们把getBean(...)方法注释掉了,当然也就没有Bean实例被创建了。
? ? ? ? ? ? ? ? 那么,如果我们在getBean(...)方法被注释掉的基础上,又将多例改为单例呢?如下图所示 :?
? ? ? ? ? ? ? ? 这时候我们再运行beanScope()方法,会发现有无参构造打印的提示信息了,如下 :?
? ? ? ? ? ? ? ? 原因我们上文也提到了——配置的Bean,默认scope="singleton"(即使你没有手动写出),若该Bean没有进行任何其他配置,默认会在容器启动时创建该Bean实例,并放入到单例池beanFactory-->singletonObjects中。
? ? ? ? ? ? ? ? 当然,如果这时候我们希望在单例形式下实现懒加载,可以在?scope="singleton"?的基础上,配置懒加载lazy-init="true",这样即使此时scope="singleton",也不会有无参构造打印出提示信息了(因为getBean被注释了,不会有Bean实例被创建),如下图所示 :?
? ? ? ? ? ? ? ? 这时候我们再运行beanScope()测试方法,会发现再一次“一无所获”,如下图所示 :?
五、关于Bean的生命周期
? ? ? ? 1.简介 :?
? ? ? ? Spring中,Bean的生命周期是指Bean从创建到初始化再到销毁的过程,这个过程由IOC容器管理,主要包括以下几个过程——
? ? ? ? ①JVM完成创建Bean对象,执行构造器。
? ? ? ? ②执行相关setter方法(Bean的属性注入)。
? ? ? ? ③调用初始化Bean的方法。(需要在beans.xml中配置Bean时,通过 init-method="method_name" 属性来指定,初始化bean的方法在setter方法后执行,具体执行时机由IOC容器来控制)
? ? ? ? ④使用Bean对象。
? ? ? ? ⑤调用销毁Bean的方法(需要在beans.xml中配置Bean时,通过 destroy-method="method_name" 属性来指定,销毁bean的方法在IOC容器关闭的时候被执行。)。
? ? ? ? 2.实例 :?
? ? ? ? ? ? ? ? 首先,我们来定义一个用于演示的JavaBean,在该JavaBean中自定义初始化Bean的方法和销毁Bean的方法。
? ? ? ? ? ? ? ? Task类代码如下 :?
package com.cyan.spring.bean;
public class Task {
private String taskName;
public Task() {
System.out.println("Task 类的无参构造器被执行~");
}
public Task(String taskName) {
this.taskName = taskName;
}
public String getTaskName() {
return taskName;
}
public void setTaskName(String taskName) {
System.out.println("(IOC容器通过setter进行Bean的属性注入)The taskName you set is : " + taskName);
this.taskName = taskName;
}
//初始化Bean的方法
public void init() {
System.out.println(this.getTaskName() + " is initiated~");
}
//销毁Bean的方法
public void destroy() {
System.out.println(this.getTaskName() + " is destroyed~");
}
}
? ? ? ? ? ? ? ? 然后,在beans.xml文件中配置一个Task类的Bean对象,代码如下 :?
<!-- (4) Bean生命周期 -->
<bean class="com.cyan.spring.bean.Task" id="task01"
init-method="init" destroy-method="destroy">
<property name="taskName" value="不动鸣神,泡影断灭"></property>
</bean>
? ? ? ? ? ? ? ? 接着,仍然是在StudentBeanByXML测试类中定义一个单元测试方法,输出获取到的Bean对象,查看无参构造,setter方法,以及自定义的初始化Bean和销毁Bean的方法有没有打印出提示信息。beanLifeCycle()方法代码如下 :?
//(4) 测试 Bean生命周期
@Test
public void beanLifeCycle() {
//回顾———接口的多态
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Object task01 = ioc.getBean("task01");
System.out.println("task01 = " + ((Task)task01));
//若想使用close方法,需要强制向下转型(此处的接口的向下转型)
((ConfigurableApplicationContext) ioc).close();
}
? ? ? ? ? ? ? ? 运行结果 :?
六、Bean配置后置处理器
? ? ? ? 1.简介 :?
? ? ? ? (1) 在Spring的IOC容器中,可以配置bean的后置处理器,后置处理器的本质其实是一个实现了BeanPostProcessor接口的Java类。
? ? ? ? (2) 后置处理器通常会实现BeanPostProcessor接口中的两个方法,这两个方法允许该后置处理器在Bean的初始化方法(即配置Bean时init-method属性所指定的初始化方法)调用前和调用后进行相应的业务处理(即程序员可以在这两个方法中处理自己的代码)。其实,我们可以直接“见名知意”,这两个方法分别为postProcessBeforeInitialization(...) 和 postprocessAfterInitialization(...)。
? ? ? ? (3) 当我们在XML文件中配置了后置处理器,后置处理器对象会作用于当前IOC容器中所有创建的Bean对象(体现了AOP[面向切面编程]);“对IOC容器中所有创建的Bean对象的统一处理”可以应用于日志处理、权限校验、安全验证,事务管理等业务场景。
? ? ? ? 2.实例 :?
? ? ? ? ? ? ? ? 就以上文中定义的Task类为JavaBean类(我们之前在该类中业已定义了初始化Bean的方法和销毁Bean的方法),我们还需要定义一个后置处理器,CyanBeanPostProcessor类代码如下 :?
package com.cyan.spring.bean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class CyanBeanPostProcessor implements BeanPostProcessor {
/**
* postProcessBeforeInitialization(...)方法在Bean的init方法执行前被调用
* @param bean : IOC容器中创建的Bean对象
* @param beanName : 传入的该Bean对象的id属性值
* @return : 通常返回业务处理后的bean对象。
* @throws BeansException : 执行过程中若出现异常,抛出BeansException
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization方法被调用" + ", bean=" + bean + " beanName=" + beanName);
return bean;
}
/**
* postProcessAfterInitialization(...)方法在Bean的init方法执行后被调用(注意调用顺序)
* @param bean : IOC容器中创建的Bean对象
* @param beanName : 传入的该Bean对象的id属性值
* @return : 通常返回业务处理后的bean对象。
* @throws BeansException : 执行过程中若出现异常,抛出BeansException
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization方法被调用" + ", bean=" + bean + " beanName=" + beanName);
return bean;
}
}
? ? ? ? ? ? ? ? 为了更好的演示Bean的后置处理器,up在src目录下新建了一个beans_EX.xml配置文件。在beans_EX.xml配置文件中,我们需要配置一个Task类的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.xsd">
<!-- 配置Task类Bean对象 -->
<bean class="com.cyan.spring.bean.Task" id="task01"
init-method="init" destroy-method="destroy">
<property name="taskName" value="高墙谍影"></property>
</bean>
<!-- 配置后置处理器对象 -->
<bean class="com.cyan.spring.bean.CyanBeanPostProcessor" id="beanPostProcessor01"/>
</beans>
? ? ? ? ? ? ? ? 最后,仍然是在StudentBeanByXML测试类中新定义一个单元测试方法,测试后置处理器实现的两个方法是否被调用。
? ? ? ? ? ? ? ? beanPostProcessor()方法代码如下 :
//(5) 测试 Bean后置处理器
@Test
public void beanPostProcessor() {
//注意此处获取IOC容器时,传入的实参变成了beans_EX.xml
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans_EX.xml");
Object task01 = ioc.getBean("task01");
System.out.println("task01 = " + ((Task)task01));
((ConfigurableApplicationContext) ioc).close();
}
? ? ? ? ? ? ? ? 运行结果 :?
? ? ? ? ? ? ? ? 可以看到,仍然满足上文中Bean的生命周期的五个过程;并且在此基础上,初始化Bean的方法执行前调用了postProcessBeforeInitialization(...)方法,而初始化Bean的方法执行后调用了postProcessAfterInitialization(...)方法。
七、通过.properties文件为Bean注入属性
? ? ? ? 1.简介 :?
????????在XML中通过命名空间<context:property-placeholder location="classpath:__.properties"/>指定一个属性文件,在该属性文件中为Bean的属性赋值。其中,location属性表示文件所在的位置(注意格式)。
? ? ? ? 在配置Bean时,以"${key}"的形式引用属性文件中定义的属性值。
? ? ? ? 2.实例 :?
? ? ? ? ? ? ? ? 首先我们需要在src目录下建立一个自定义的properties文件。up以cyan.properties为例,如下所示 :?
? ? ? ? ? ? ? ? 以上文“关于Bean的创建顺序”中定义的Commodity类为JavaBean类,在cyan.properties属性文件中为Bean属性赋值:
id=1
name=Camera
price=12999
?????????????????继续回到我们的beans.xml中进行配置,将上文“Bean的生命周期”中配置的Task类Bean对象注释掉,防止打印出的信息造成干扰。在beans.xml中配置一个Commodity类型的Bean对象,并指定相应的属性文件,代码如下 :?
<!-- (6) 通过属性文件为Bean注入属性 -->
<!-- 配置一个Commodity对象 -->
<bean class="com.cyan.spring.bean.Commodity" id="commodity01">
<property name="id" value="${id}"></property>
<property name="name" value="${name}"></property>
<property name="price" value="${price}"></property>
</bean>
<!-- 指定一个属性文件为该Commodity对象的属性赋值 -->
<context:property-placeholder location="classpath:cyan.properties"/>
? ? ? ? ? ? ? ? 在测试类中新定义一个单元测试方法,测试为Bean输入属性是否成功。
????????????????injectBeanByProperties()方法代码如下 :?
//(6) 测试 通过属性文件为Bean注入属性
@Test
public void injectBeanByProperties() {
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Commodity commodity01 = ioc.getBean("commodity01", Commodity.class);
System.out.println("commodity01 = " + commodity01);
}
? ? ? ? ? ? ? ? 运行结果 :?
八、关于Bean的自动装配
? ? ? ? 1.简介 :?
? ? ? ? 前面我们在讲“通过ref引用实现Bean的相互引用”时提到,在Spring中,可以通过ref引用实现“Web层调用Service层,Service层调用DAO层”的分层设计思想,如下图所示? :(回顾)
????????而“Bean的自动装配”,其实就是以另一种更快捷的方式来达到这个效果。
? ? ? ? Bean的自动装配,需要在配置Bean时通过autowire属性来实现。
? ? ? ? Δautowire属性又主要有两种常用的属性值——byType 和 byName。
? ? ? ? ①byType,指通过类型给Bean对象的属性完成赋值,即根据属性的类型在IOC容器中匹配有没有相同的类型的Bean对象(要求当前IOC容器中有且至多有一个对应类型的Bean对象),若匹配成功则自动装配。
? ? ? ? ②byName,指通过setter方法的名称给Bean对象的属性完成赋值,即根据setXxx方法的xxx (字面意思),去IOC容器中寻找"id=xxx"的Bean对象,若匹配成功则自动装配。
? ? ? ? 2.实例 :?
? ? ? ? ? ? ? ? 先来演示autowire="byType"的情况。
? ? ? ? ? ? ? ? 基于"Web层调用Service层,Service层调用DAO层"的思想,我们先来定义三个演示类OrderServlet, OrderServiceImpl, OrderDAOImpl。
? ? ? ? ? ? ? ? OrderDAOImpl类代码如下 :?
package com.cyan.spring.dao;
public class OrderDAOImpl {
public void saveOder() {
System.out.println("保存了订单...");
}
}
? ? ? ? ? ? ? ? OrderServiceImpl类代码如下 :?
package com.cyan.spring.service;
import com.cyan.spring.dao.OrderDAOImpl;
public class OrderServiceImpl {
private OrderDAOImpl orderDAO;
public OrderDAOImpl getOrderDAO() {
return orderDAO;
}
public void setOrderDAO(OrderDAOImpl orderDAO) {
this.orderDAO = orderDAO;
}
}
? ? ? ? ? ? ? ? OrderServlet类代码如下 :?
package com.cyan.spring.web;
import com.cyan.spring.service.OrderServiceImpl;
public class OrderServlet {
private OrderServiceImpl orderService;
public OrderServiceImpl getOrderService() {
return orderService;
}
public void setOrderService(OrderServiceImpl orderService) {
this.orderService = orderService;
}
}
????????????????接着,在beans.xml中分别配置OrderDAOImpl,OrderServiceImpl,OrderServlet类的Bean对象,代码如下 :?
<!-- (7) Bean自动装配 -->
<!-- OrderDAOImpl类中没有定义属性,因此不需要配置autowire -->
<bean class="com.cyan.spring.dao.OrderDAOImpl" id="orderDAO01"/>
<bean autowire="byType" class="com.cyan.spring.service.OrderServiceImpl" id="orderService01"/>
<bean autowire="byType" class="com.cyan.spring.web.OrderServlet" id="orderServlet01"/>
? ? ? ? ? ? ? ? 最后,在测试类中定义单元测试方法,beanAutoAssemble()方法代码如下 :?
//(7) 测试 Bean的自动装配
@Test
public void beanAutoAssemble() {
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
OrderServlet orderServlet01 = ioc.getBean("orderServlet01", OrderServlet.class);
System.out.println("orderServlet01" + orderServlet01);
System.out.println("orderServiceImpl01" + orderServlet01.getOrderService());
System.out.println("orderDAOImpl" + orderServlet01.getOrderService().getOrderDAO());
}
? ? ? ? ? ? ? ? 运行结果 :?
????????????????再来演示autowire="byName"的情况。
? ? ? ? ? ? ? ? 假设我们直接将原先配置的OrderServlet和OrderServiceImpl的autowire改为byName,如下图所示 :?
? ? ? ? ? ? ? ? 由于setOrderService方法和setOrderDAO对应的xxx分别为"orderService"和"orderDAO",因此会匹配IOC容器中 id=orderService 和 id=orderDAO的Bean对象,而我们此时只有id=orderDAO01 和 id=orderService01的Bean对象,因此匹配失败,可以猜到测试方法会报错空指针异常(不能正常调用getOrderDAO()方法),我们尝试运行,结果如下 :?
? ? ? ? ? ? ? ? 果然如此,此时,解决方法有两个——①修改配置的Bean对象的id为setter方法对应的xxx;②修改setter方法的名称,使之与已配置的Bean的id匹配。这里up以解决方法①为例,如下图所示 ;?
? ? ? ? ? ? ? ? 这时,我们再次运行beanAutoAssemble()方法,结果如下 :?
? ? ? ? ? ? ? ? 果然如此。
九、关于Spring-EL表达式
? ? ? ? 1.简介 :?
? ? ? ? (1) Spring Expression Language,简称SpEL,指Spring表达式语言,支持运行时查询并操作对象,类似于EL表达式,SpEL根据JavaBean的getXxx()、setXxx()方法定义的属性访问对象。
? ? ? ? (2) SpEL使用#{...}作为定界符,所有在{}中的字符都将被认为是SpEL表达式。
? ? ? ? 2.实例 :?
? ? ? ? ? ? ? ? 首先建立一个新的JavaBean,以Cat类为例,Cat类代码如下:?
package com.cyan.spring.bean;
public class Cat {
//fields
private String name;
private int age;
private String food;
private String habit;
//constructor
public Cat() {
}
public Cat(String name, int age, String food, String habit) {
this.name = name;
this.age = age;
this.food = food;
this.habit = habit;
}
//getter, setter
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getFood() {
return food;
}
public void setFood(String food) {
this.food = food;
}
public String getHabit() {
return habit;
}
public void setHabit(String habit) {
this.habit = habit;
}
//非静态方法
public String eat(String food) {
return food;
}
//静态方法
public static String like(String habit) {
return habit;
}
//重写toString()方法
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
", age=" + age +
", food='" + food + '\'' +
", habit='" + habit + '\'' +
'}';
}
}
? ? ? ? ? ? ? ? 在beans.xml中通过SpEL配置Cat类Bean对象,代码如下 :?
<!-- (8) SpEL表达式 -->
<bean class="com.cyan.spring.bean.Cat" id="cat01">
<property name="name" value="lit"></property>
<property name="age" value="2"></property>
<property name="food" value="meat"></property>
<property name="habit" value="sleep"></property>
</bean>
<bean class="com.cyan.spring.bean.Cat" id="cat02">
<property name="name" value="#{'cro'}"></property>
<!-- 使用SpEL可以引用其他Bean的属性 -->
<property name="age" value="#{cat01.age - 1}"></property>
<!-- 使用SpEL可以调用非静态方法,并以其返回值赋值 -->
<property name="food" value="#{cat01.eat('fish')}"></property>
<!-- 使用SpEL可以调用静态方法,并以其返回值赋值 -->
<property name="habit" value="#{T(com.cyan.spring.bean.Cat).like('playing')}"></property>
</bean>
? ? ? ? ? ? ? ? 最后,仍然是在测试类中定义一个单元测试方法,测试id=cat02的Bean对象的属性是否注入成功。
? ? ? ? ? ? ? ? testSpringEL()方法代码如下 :?
//(8) 测试 Spring-EL表达式
@Test
public void testSpringEL() {
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Cat cat02 = ioc.getBean("cat02", Cat.class);
System.out.println("cat02 = " + cat02);
}
? ? ? ? ? ? ? ? 运行结果 :?
十、总结?
????????🆗,以上就是“关于Bean配置的更多内容和细节”的全部内容了,虽然本篇博文是只是对
“Spring IOC——基于XML方式对Bean的配置和管理”一文的内容补充,但由于“Spring——基于XML配置和管理Bean”本身内容较多,所以这篇补充性质的文章篇幅也不短,希望大家勤动手,自己写一些,感谢阅读!。
? ? ? ? System.out.println("END-----------------------------);?
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!