#Spring工厂类介绍
在前面使用了Spring的ApplicationContext
,并通过它的getBean方法获取Spring的配置文件applicationContext.xml
,然后得到Bean的class对象。
从图中可以知道我们使用的是ApplicationContext
接口,而使用的具体实现类是ClassPathXmlApplicationContext
用来加载类路径下面的配置文件;注意到左边还有一个FileSystemXmlApplicationContext
实现类,用于加载文件系统中的文件,言外之意就是当你的配置文件不在当前的项目工程内,此时就可以使用FileSystemXmlApplicationContext
实现类去获取配置文件,接着去获取Bean对象。在老旧的Spring中使用的是BeanFactory
接口,正如你所看到的ApplicationContext
接口是它的子类自然功能就相对来说较为丰富。再有一点就是两者在生成Bean实例的时间是不同的。对于BeanFactory
接口来说是工厂实例化结束后,在调用getBean方法的时才会去创建该类的实例;而ApplicationContext
接口则是一开始加载配置文件的时候,就会将配置文件中所有通过单例模式创建的对象都给实例化,一般都会使用后者:
/**
* Spring开发模式:读取磁盘系统中的配置文件
**/
@Test
public void testThree(){
ApplicationContext applicationContext = new FileSystemXmlApplicationContext("D:\\Maven\\applicationContext.xml");
UserServiceImpl userServiceimpl = (UserServiceImpl) applicationContext.getBean("userService");
//调用对象的方法
System.out.println(userServiceimpl.getName());
userServiceimpl.sayHello();
}
在Spring中管理Bean有两种方式:XML方式和注解方式,先介绍XML方式。在Spring中实例化Bean的方式有三种:1、使用类构造器实例化(默认无参数);2、使用静态工厂方法实例化(简单工厂模式);3、使用实例工厂方法实例化(工厂方法模式)
在java包中新建一个com.envy.demo的文件夹,接着新建一个Bean1.java
文件:
public class Bean1 {
/**
* 使用无参数的类构造器实例化Bean
*/
public Bean1(){
System.out.println("使用无参数的类构造器实例化Bean");
}
}
接着在applicationContext.xml
文件中新增一个Bean:
<!-- Bean实例化的三种方式 -->
<!-- 第一种,使用无参数的类构造器实例化Bean -->
<bean id="bean1" class="com.envy.demo.Bean1"></bean>
最后新建一个SpringBeanTest.java
的测试文件:
public class SpringBeanTest {
/**
*
* Bean实例化的三种方式
**/
@Test
public void testOne(){
/**
* 使用无参数的构造函数实例化Bean
* **/
//获得Spring工厂
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Bean1 bean1 = (Bean1)applicationContext.getBean("bean1");
}
运行testOne方法,发现控制台输出:
使用无参数的类构造器实例化Bean
在java包中新建一个com.envy.demo的文件夹,接着新建一个Bean2.java
文件:
public class Bean2{
}
接着在该包中新建Bean2Factory.java
文件,用于作为静态工厂实例化Bean2:
public class Bean2Factory {
public static Bean2 createBean2(){
System.out.println("使用静态工厂实例化Bean");
return new Bean2();
}
}
然后在applicationContext.xml
文件中新增一个Bean:
<!-- Bean实例化的三种方式 -->
<!-- 第二种,使用静态工厂实例化Bean -->
<bean id="bean2" class="com.envy.demo.Bean2Factory" factory-method="createBean2"></bean>
最后在SpringBeanTest.java
测试文件中添加testTwo方法:
@Test
public void testTwo(){
/**
* 使用静态工厂实例化Bean
* **/
//获得Spring工厂
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Bean2 bean2 = (Bean2)applicationContext.getBean("bean2");
}
运行testTwo方法,发现控制台输出:
使用无参数的类构造器实例化Bean
使用静态工厂实例化Bean
你会发现之前的testOne方法也被执行了,这个是正常现象,因为该工厂ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
只要加载配置文件就会将该配置文件中所有的类都给实例化。
如果你不想看到testOne方法被执行输出,可以将applicationContext.xml
文件中的<bean id="bean1" class="com.envy.demo.Bean1"></bean>
给注释掉即可。
在java包中新建一个com.envy.demo的文件夹,接着新建一个Bean3.java
文件:
public class Bean3{
}
接着在该包中新建Bean3Factory.java
文件,用于作为实例工厂实例化Bean3:
public class Bean3Factory {
/**
* Bean3的实例工厂
**/
public Bean3 createBean3(){
System.out.println("使用实例工厂实例化Bean");
return new Bean3();
}
}
然后在applicationContext.xml
文件中新增一个Bean:
<!-- Bean实例化的三种方式 -->
<!-- 第三种,使用实例工厂实例化Bean -->
<bean id="bean3Factory" class="com.envy.demo.Bean3Factory"></bean>
<bean id="bean3" factory-bean="bean3Factory" factory-method="createBean3"></bean>
实例方法和静态方法的区别是前者的调用必须依赖于对象,而后者可以通过类名来调用。因此此处的bean3必须要依靠bean3Factory对象,所以先获取bean3Factory对象,接着把bean3Factory对象作为factory-bean来生成bean3对象。
最后在SpringBeanTest.java
测试文件中添加testThree方法:
@Test
public void testThree(){
/**
* 使用实例工厂实例化Bean
* **/
//获得Spring工厂
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Bean3 bean3 = (Bean3) applicationContext.getBean("bean3");
}
运行testThree方法,发现控制台输出:
使用实例工厂实例化Bean
通常情况下我们会使用第一种,也就是默认的无参数的构造函数方式来实例化Bean,除非你的类的构造非常复杂才会使用后面三种。
一般而言在Bean在使用最多的就是id和name,通常装配一个Bean时指定一个id属性作为Bean的名称,注意id属性在IOC容器中必须是唯一的;name和id属性的区别不大,当id中出现一些特殊字符时,则必须使用name属性,Id属性中不能包含特殊字符。
class属性用于设置一个类的完全路径名称,主要作用是IOC容器生成类的实例。
Bean的作用域是通过scope属性来设置的,其中scope的值有以下几种:
前面两个较为常用,后面两个不常用,一般用于web项目。scope属性默认值是singleton,也就是单例模式。你可以测试一下,先创建一个Bean4.java
文件:
public class Bean4 {
}
然后在applicationContext.xml
文件中新增一个Bean:
<!-- 测试Bean的作用域 -->
<bean id="bean4" class="com.envy.demo.Bean4"></bean>
最后在SpringBeanTest.java
测试文件中添加testFour方法:
@Test
public void testFour(){
/**
* 测试Bean的作用域
* **/
//获得Spring工厂
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Bean4 bean41 = (Bean4) applicationContext.getBean("bean4");
Bean4 bean42 = (Bean4) applicationContext.getBean("bean4");
System.out.println(bean41);
System.out.println(bean42);
}
运行testFour方法,发现控制台输出:
com.envy.demo.Bean4@51c8530f
com.envy.demo.Bean4@51c8530f
说明这两个对象是同一个对象,也就是scope属性默认值为singleton。
接着添加scope="prototype"
配置,然后再次运行testFour方法,发现控制台输出:
com.envy.demo.Bean4@51c8530f
com.envy.demo.Bean4@7403c468
说明这是两个不同的对象,每次调用getBean方法都会生成一个新的实例。
Spring初始化bean或销毁bean时,有时需要进行一些处理工作,因此spring可以在创建和销毁bean的时候调用Bean的两个生命周期方法:init-method
和destory-method
:
<bean id="test" class="com.envy.demo.Test" init-method="init" destroy-method="destory"></bean>
当bean被加载到容器的时候调用init
方法;当bean从容器中删除的时候调用destory
方法(注意destory
方法必须是当scope=singleton时才有效,因为当你不是单例的时候,destory
方法不知道你具体需要删除哪个实例)。前面说过scope默认是singleton,因此可以不写scope即可。
你可以测试一下,先创建一个Bean5.java
文件:
public class Bean5 {
public Bean5(){
System.out.println("Bean5被实例化了");
}
public void initBean5(){
System.out.println("Bean5被初始化了");
}
public void destroyBean5(){
System.out.println("Bean5被销毁了");
}
}
然后在applicationContext.xml
文件中新增一个Bean:
<!-- 测试Bean的生命周期 -->
<bean id="bean5" class="com.envy.demo.Bean5" init-method="initBean5" destroy-method="destroyBean5"></bean>
最后在SpringBeanTest.java
测试文件中添加testFive方法:
@Test
public void testFive(){
/**
* 测试Bean的生命周期
* **/
//获得Spring工厂
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Bean5 bean5 = (Bean5) applicationContext.getBean("bean5");
System.out.println(bean5);
((ClassPathXmlApplicationContext) applicationContext).close();
}
运行testFive方法,发现控制台输出:
Bean5被实例化了
Bean5被初始化了
com.envy.demo.Bean5@51c8530f
Bean5被销毁了
接下来通过之前的Bean5来介绍Bean的整个完整的生命周期过程。
第一步:Bean对象实例化。前面代码已经完成。
第二步:封装Bean对象属性。打开Bean5.java文件,修改代码为:
public class Bean5 {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("第二步:封装name属性");
this.name = name;
}
public Bean5(){
System.out.println("第一步:Bean5被实例化了");
}
public void initBean5(){
System.out.println("Bean5被初始化了");
}
public void destroyBean5(){
System.out.println("Bean5被销毁了");
}
}
既然封装了某个属性,那么需要去applicationContext.xml
文件中新增property:
<bean id="bean5" class="com.envy.demo.Bean5" init-method="initBean5" destroy-method="destroyBean5">
<property name="name" value="这是测试完整的Bean生命周期"></property>
</bean>
第三步:如果Bean实现BeanNameAware,那么必须重写setBeanName方法。
第四步:如果Bean实现BeanFactoryAware,则需重写setBeanFactory方法(或者实现ApplicationContextAware,并重写上下文对象setApplicationContext方法,两者二选一)。
可以看出其实第三步和第四步是让我们这个Bean来了解自己在Spring容器中的信息,如名字、工厂等信息。
其实第三步就是获取Bean在Spring容器中配置信息,即name或者id值。在Bean5.java文件中让Bean5实现BeanNameAware
接口,并新增以下代码:
public void setBeanName(String name) {
//这里的name其实就是applicationContext.xml中Bean的id的值
System.out.println("第三步:设置Bean的名称"+name);
}
第四步是让Bean去了解工厂的信息。在Bean5.java文件中让Bean5实现ApplicationContextAware
接口,并新增以下代码:
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("第四步:了解工厂信息");
}
这其中的第五步和第八步是较为核心的步骤。第五步,如果存在类实现BeanPostProcessor(后处理Bean),则会执行其中的postProcessBeforeInitialization
方法。
先创建一个MyBean5PostProcessor.java
文件,去实现BeanPostProcessor接口,并重写其中的两个方法(一般该两个方法均有返回值):
public class MyBean5PostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String s) throws BeansException {
System.out.println("第五步:这是初始化前的方法...");
return bean;
}
public Object postProcessAfterInitialization(Object bean, String s) throws BeansException {
System.out.println("第八步:这是初始化后的方法...");
return bean;
}
}
既然新建了一个类,就得去applicationContext.xml
文件中新增一个Bean:
<bean class="com.envy.demo.MyBean5PostProcessor"></bean>
请注意该Bean没有id属性,因为通常设置id属性是可以让你在工厂或者其他地方可以使用到该类,而这个MyBean5PostProcessor类Spring则会在生成类的实例过程中会自动去调用,并不需要其他地方去引用,因此无需配置id。
第六步,如果Bean实现InitializingBean,那么必须重写afterPropertiesSet方法。让Bean5类去实现InitializingBean
接口,并重写afterPropertiesSet
方法:
public void afterPropertiesSet() throws Exception {
System.out.println("第六步:属性设置完后就会调用");
}
第七步,执行applicationContext.xml
文件中<bean id="bean5" init-method="initBean5">
中的指定的init-method方法initBean5
。修改Bean5.java文件中的initBean5方法代码:
public void initBean5(){
System.out.println("第七步:Bean5被初始化了");
}
第八步,如果存在类实现BeanPostProcessor(后处理Bean),则会执行其中的postProcessAfterInitialization
方法。
第九步,执行Bean5.java
文件中自身的逻辑方法,如定义一个run方法:
public void run(){
System.out.println("第九步:执行自身业务逻辑方法");
}
第十步,如果Bean实现DisposableBean
接口,那么必须重写destroy
方法。让Bean5类去实现DisposableBean
接口,并重写destroy
方法:
public void destroy() throws Exception {
System.out.println("第十步:执行Spring中的destroy方法");
}
第十一步,执行applicationContext.xml
文件中<bean id="bean5" destroy-method="destroyBean5>
中的指定的destroy-method方法destroyBean5
。修改Bean5.java文件中的destroyBean5方法代码:
public void destroyBean5(){
System.out.println("第十一步:Bean5被销毁了");
}
最后在SpringBeanTest.java测试文件中添加testSix方法:
@Test
public void testSix(){
/**
* 测试Bean的完整生命周期
* **/
//获得Spring工厂
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Bean5 bean5 = (Bean5) applicationContext.getBean("bean5");
bean5.run();
((ClassPathXmlApplicationContext) applicationContext).close();
}
运行testSix方法,发现控制台输出:
第一步:Bean5被实例化了
第二步:封装name属性
第三步:设置Bean的名称bean5
第四步:了解工厂信息
第五步:这是初始化前的方法...
第六步:属性设置完后就会调用
第七步:Bean5被初始化了
第八步:这是初始化后的方法...
第九步:执行自身业务逻辑方法
第十步:执行Spring中的destroy方法
第十一步:Bean5被销毁了
前面也说过这里面最重要的是第五步和第八步(后处理Bean),它是在我们整个类的生成过程中需要执行的一个步骤,它可以在不修改Bean中的代码实现对类功能的增强。
前面说过BeanPostProcessor(后处理类)可以在生成类的过程中对类进行代理,且可以对其中的方法进行增强。接下来通过面向接口的方式来演示如何增强一个类中的方法。
新建一个UserDao.java的接口文件:
public interface UserDao {
public void findAll();
public void save();
public void update();
public void delete();
}
接着新建一个UserDaoImpl.java文件,去实现它并重写其中的方法:
public class UserDaoImpl implements UserDao {
public void findAll() {
System.out.println("查询用户");
}
public void save() {
System.out.println("保存用户");
}
public void update() {
System.out.println("修改用户");
}
public void delete() {
System.out.println("删除用户");
}
}
既然新建了一个类,就得去applicationContext.xml文件中新增一个Bean:
<bean id="userDao" class="com.envy.demo.UserDaoImpl"></bean>
接着注释掉其中一些没有的代码,只保留以下代码:
<bean class="com.envy.demo.MyBean5PostProcessor"></bean>
<!-- 测试BeanPostProcessor的作用 -->
<bean id="userDao" class="com.envy.demo.UserDaoImpl"></bean>
最后在SpringBeanTest.java测试文件中添加testSeven方法:
@Test
public void testSeven(){
/**
* 测试BeanPostProcessor的作用
* **/
//获得Spring工厂
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) applicationContext.getBean("userDao");
userDao.findAll();
userDao.save();
userDao.update();
userDao.delete();
}
运行testSeven方法,发现控制台输出:
第五步:这是初始化前的方法...
第八步:这是初始化后的方法...
查询用户
保存用户
修改用户
删除用户
确实调用了MyBean5PostProcessor文件中的方法并进行输出。MyBean5PostProcessor中的两个方法目前只是直接返回了Bean实例,其实是可以返回一个代理对象的,因此可以先对Bean进行处理,最后返回一个代理对象即可。或者说需要对UserDaoImpl类中的save方法进行功能上增强,如增加权限控制。实现这个过程只需要在MyBean5PostProcessor类中修改postProcessAfterInitialization方法即可:
public Object postProcessAfterInitialization(final Object bean, String beanName) throws BeansException {
System.out.println("第八步:这是初始化后的方法...");
if ("userDao".equals(beanName)) {
Object proxy = Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("save".equals(method.getName())) {
System.out.println("执行对应的权限操作验证");
return method.invoke(bean, args);
}
return method.invoke(bean, args);
}
});
return proxy;
}
return bean;
}
}
最后在SpringBeanTest.java测试文件中运行testSeven方法,发现控制台输出:
第五步:这是初始化前的方法...
第八步:这是初始化后的方法...
查询用户
执行对应的权限操作验证
保存用户
修改用户
删除用户
看到没有我们并没有在实现类中进行任何操作,仅仅在postProcessAfterInitialization方法中进行了处理就实现了相应的功能。
spring在创建类的过程中会将类依赖的属性注入进来,接下是spring类的属性注入方式。对于类成员变量而言,注入方式有三种:1、构造函数注入;2、属性setter方法注入;3、接口注入(不常用)。但是Spring只支持前两种也就是构造函数注入和属性setter方法注入。
通过构造方法注入Bean的属性值或依赖的对象,它保证了Bean实例在实例化后就可以使用。构造器注入在<constructor-arg>元素里声明的属性。
第一步:新建Bean6.java文件,里面的代码如下:
public class Bean6 {
private String name;
private Integer age;
public Bean6(String name,Integer age){
this.name =name;
this.age=age;
}
@Override
public String toString() {
return "Bean6{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
第二步:往applicationContext.xml文件中新增Bean6的信息:
<!-- 使用构造器函数给Bean注入属性 -->
<bean id="bean6" class="com.envy.demo.Bean6">
<constructor-arg name="name" value="张三"></constructor-arg>
<constructor-arg name="age" value="22"></constructor-arg>
</bean>
第三步:新建一个测试方法testBeanOne:
@Test
/**
* 使用构造器函数给Bean注入属性
* **/
public void testBeanOne(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Bean6 bean6 =(Bean6)applicationContext.getBean("bean6");
System.out.println(bean6);
}
运行结果:
Bean6{name='张三', age=22}
使用属性的setter方法,并通过Spring配置文件中的<property>元素来声明属性的名称及值。
第一步:新建Bean7.java文件,里面的代码如下:
public class Bean7 {
private String id;
public String getId(){
return this.id;
}
public void setId(String id){
this.id=id;
}
@Override
public String toString() {
return "Bean7{" +
"id='" + id + '\'' +
'}';
}
}
第二步:往applicationContext.xml文件中新增Bean7的信息:
<!-- 属性setter方法注入 -->
<bean id="bean7" class="com.envy.demo.Bean7">
<property name="id" value="001"></property>
</bean>
第三步:新建一个测试方法testBeanTwo:
@Test
/**
* 属性setter方法注入
* **/
public void testBeanTwo(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Bean7 bean7 =(Bean7)applicationContext.getBean("bean7");
System.out.println(bean7);
}
运行结果:
Bean7{id='001'}
其实在实际中setter属性注入是用的较多的方法,而更多的被用在属性是引用对象的情况,如现在的Bean6有一个属性是Bean7,则应该怎么修改代码呢?按照下面的步骤进行:
第一步:新建Bean67.java文件,里面的代码如下:
public class Bean67 {
private String name;
private Integer age;
private Bean7 bean7;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Bean7 getBean7() {
return bean7;
}
public void setBean7(Bean7 bean7) {
this.bean7 = bean7;
}
@Override
public String toString() {
return "Bean67{" +
"name='" + name + '\'' +
", age=" + age +
", bean7=" + bean7 +
'}';
}
}
第二步:往applicationContext.xml文件中新增Bean67信息:
<!-- 属性setter方法注入 -->
<bean id="bean7" class="com.envy.demo.Bean7">
<property name="id" value="001"></property>
</bean>
<bean id="bean67" class="com.envy.demo.Bean67">
<property name="name" value="张三"></property>
<property name="age" value="22"></property>
<property name="bean7" ref="bean7"></property> //ref中为引用对象的id或者name
</bean>
第三步:新增测试方法testBeanThree:
@Test
/**
* 属性setter方法注入(参数中包含引用对象)
* **/
public void testBeanThree(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Bean67 bean67 =(Bean67)applicationContext.getBean("bean67");
System.out.println(bean67);
}
运行结果:
Bean67{name='张三', age=22, bean7=Bean7{id='001'}}
也就是说普通属性的注入使用name,而引用属性使用ref,这种方式在构造方法中注入也是适用的。
当然还可以使用p名称空间的方法来实现属性的注入,它是为了简化xml文件配置,从Spring2.5开始引入的。使用p:<属性名>="xxx"
引入常量值;使用p:<属性名>-ref="xxx"
引用其他Bean对象。
接下来使用前面介绍的Bean67进行p名称空间属性注入的演示。你只需要注释前面的配置,并使下面的配置生效即可:
<!-- 导入p名称空间 -->
xmlns:p="http://www.springframework.org/schema/p"
<!-- 属性p名称空间注入 -->
<bean id="bean7" class="com.envy.demo.Bean7" p:id="001"></bean>
<bean id="bean67" class="com.envy.demo.Bean67" p:name="李四" p:age="18" p:bean7-ref="bean7"></bean>
SpEL(Spring Expression Language),使用Spring表达式语言对依赖注入进行简化。语法是#{表达式}
,通常是<bean id="xxx" value="#{表达式}">
。下面介绍一些常用的SpEL的用法:1、传递变量使用#{变量名称}
;2、传递字符串使用#{'字符串名称'}
;3、使用另一个Bean对象采用#{helloId2}
;4、使用指定名属性且使用方法#{world.print.toUpperCase()}
;5、使用静态字段或者方法#{T(java.lang.Math).PI}
等等。
下面通过product和Category这两个类来演示SpEL的属性注入。
第一步,新建Product.java文件,里面的代码如下:
public class Product {
private String name;
private double price;
private Category category;
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;
}
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
@Override
public String toString() {
return "Product{" +
"name='" + name + '\'' +
", price=" + price +
", category=" + category +
'}';
}
}
以及Category.java文件,里面的代码如下:
public class Category {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Category{" +
"name='" + name + '\'' +
'}';
}
}
第二步,往applicationContext.xml文件中新增以下代码:
<!-- SpEL属性注入 -->
<bean id="product" class="com.envy.demo.Product">
<property name="name" value="#{'童装'}"></property>
<property name="price" value="#{99.00}"></property>
<property name="category" value="#{category}"></property> <!-- 注意value的值必须是引用对象Bean的id或者name属性 -->
</bean>
<bean id="category" class="com.envy.demo.Category">
<property name="name" value="#{'001'}"></property>
</bean>
第三步,新增测试方法testBeanFour:
@Test
/**
* 属性SpELl方法注入(参数中包含引用对象)
* **/
public void testBeanFour(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Product product =(Product) applicationContext.getBean("product");
System.out.println(product);
}
运行结果:
Product{name='童装', price=99.0, category=Category{name='001'}}
现在只是单纯的使用到了引用对象的属性,接下来演示引用对象的方法注入。
可以新建一个ProductPrice.java文件:
public class ProductPrice {
public double CalcPrice(){
return Math.random()*99;
}
}
接着修改applicationContext.xml文件为:
<!-- SpEL属性注入 -->
<bean id="product" class="com.envy.demo.Product">
<property name="name" value="#{'童装'}"></property>
<property name="price" value="#{productPrice.CalcPrice()}"></property>
<property name="category" value="#{category}"></property> <!-- 注意value的值必须是引用对象Bean的id或者name属性 -->
</bean>
<bean id="productPrice" class="com.envy.demo.ProductPrice"></bean>
<bean id="category" class="com.envy.demo.Category">
<property name="name" value="#{'001'}"></property>
</bean>
最后运行一下测试方法testBeanFour,结果为:
Product{name='童装', price=21.540606263709023, category=Category{name='001'}}
复杂类型是指属性为数组、List、Map、Set、Properties类型。
新建一个CollectionBean.java文件,里面的代码如下:
public class CollectionBean {
private String[] stringArray; //数组类型
private List<String> stringList; //列表类型
private Set<String> stringSet; //集合类型
private Map<String,Integer> stringIntegerMap; //map类型
private Properties properties; //属性类型
public String[] getStringArray() {
return stringArray;
}
public void setStringArray(String[] stringArray) {
this.stringArray = stringArray;
}
public List<String> getStringList() {
return stringList;
}
public void setStringList(List<String> stringList) {
this.stringList = stringList;
}
public Set<String> getStringSet() {
return stringSet;
}
public void setStringSet(Set<String> stringSet) {
this.stringSet = stringSet;
}
public Map<String, Integer> getStringIntegerMap() {
return stringIntegerMap;
}
public void setStringIntegerMap(Map<String, Integer> stringIntegerMap) {
this.stringIntegerMap = stringIntegerMap;
}
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
@Override
public String toString() {
return "CollectionBean{" +
"stringArray=" + Arrays.toString(stringArray) +
", stringList=" + stringList +
", stringSet=" + stringSet +
", stringIntegerMap=" + stringIntegerMap +
", properties=" + properties +
'}';
}
}
接着注释掉applicationContext.xml文件中的其他代码,添加以下代码:
<!-- 复杂(集合)类型的属性注入 -->
<bean id="collectionBean" class="com.envy.demo.CollectionBean">
<!-- 数组类型属性注入 -->
<property name="stringArray">
<list>
<value>数组1</value>
<value>数组2</value>
<value>数组3</value>
</list>
</property>
<!-- List类型属性注入 -->
<property name="stringList">
<list>
<!-- 普通属性用value -->
<value>List1</value>
<value>List2</value>
<!-- 对象属性使用ref -->
<!--<ref>List3</ref>-->
<!--<ref>List4</ref>-->
</list>
</property>
<!-- Set类型属性注入 -->
<property name="stringSet">
<set>
<value>Set1</value>
<value>Set2</value>
<value>Set3</value>
</set>
</property>
<!-- Map类型属性注入 -->
<property name="stringIntegerMap">
<map>
<entry key="map1" value="01"></entry>
<entry key="map2" value="02"></entry>
<entry key="map3" value="03"></entry>
</map>
</property>
<!-- Properties类型属性注入 -->
<property name="properties">
<props>
<prop key="username">hello</prop>
<prop key="password">world</prop>
<prop key="update">good</prop>
</props>
</property>
</bean>
最后新建一个测试testBeanFive方法,里面的代码如下:
@Test
/**
* 复杂类型的属性注入
* **/
public void testBeanFive(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
CollectionBean collectionBean =(CollectionBean) applicationContext.getBean("collectionBean");
System.out.println(collectionBean);
}
运行结果为:
CollectionBean{stringArray=[数组1, 数组2, 数组3], stringList=[List1, List2], stringSet=[Set1, Set2, Set3], stringIntegerMap={map1=1, map2=2, map3=3}, properties={password=world, username=hello, update=good}}
复杂属性注入一般在进行框架整合的时候才会使用,而用的较多的属性则是properties和map。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。