目录
一、前言
- 本篇博文是对“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"/>指定一个.properties文件,在该属性文件中为Bean的属性赋值。其中,location属性表示文件所在的位置(注意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-----------------------------);