Spring之路(8)--提高资源管理的灵活性(使用JavaConfig定义bean)

1. 注解方式配置bean的局限性

使用注解代替xml配置bean之后,效率得到了显著提升,我们程序员写起代码了也甚是爽快,毕竟相对于编写xml,写代码无疑是更加爽快的。


使用注解定义bean的方式虽然方便快速,灵活性却有所不足,举个最简单的例子,我们使用xml可以生成同一类型的多个bean,例如下面生成了两个Singer类型的bean。


<bean id="zhoujielun" class="org.maoge.xmlbeandetail.Singer">

 <property name="name" value="周杰伦"></property>

</bean>

<bean id="linjunjie" class="org.maoge.xmlbeandetail.Singer">

 <property name="name" value="林俊杰"></property>

</bean>


但是使用注解时,一个类型下只能生成一个bean,如下:


@Component("zhoujielun")

public class Singer {

}


显然,使用注解后虽然效率提升,但是貌似功能不如xml强大了。


2. 思考如何解决

使用xml,需要额外写xml配置文件,效率低下。


而使用注解,一个注解只能加到一个类上,也就是说一个类只能生成一个bean,功能有所欠缺。


那么如何既能利用注解快速生成多个bean,同时bean还可以自定义其名称(id)和相关属性呢?


哈哈,其实不难,我们可以将注解加到方法上,然后返回值类型作为bean的类型,不就解决问题了。返回同样类型的方法可以定义任意多个,解决了对类使用注解定义bean时不能生成多个bean的问题;同时注解直接加到方法上,也不用再单独定义xml文件描述bean和其类型的关联。可谓:效率提升的同时又兼具灵活性!


3. 三种方式对比

好的,到目前为止,Spring容器中配置bean的三种方式我们都发现了:xml、注解、JavaConfig,我们来对比下:


xml功能很强,但是不够方便快速(代码量比较大)

注解非常方便快速,但是功能不够强大(有些bean描述不了)

JavaConfig比较方便快速,同时功能也足够强大

注意哈,大家可能普遍比较了解xml和注解方式,反而对比较先进的JavaConfig方式不熟悉,此处原因我认为是这样的:xml产生的比较早,网上相关的文档也比较多,所以大家比较熟悉。注解方式代码量非常精简,而且足以满足大多数场景使用,现在用的也比较多,所以大家比较熟悉;JavaConfig方式虽然足够锋利,但是由于历史等原因,目前还不足够的流行,但是其实它真的棒棒哒,我认为这种方式:真的真的很不错。


最后必须强调一点:三种方式只是方式不同,没有本质区别,都是为Spring容器提供配置信息。大家可以根据实际情况灵活选用,反正我个人是倾向于注解+JavaConfig的方式,为何?因为注解足够简单,而JavaConfig足够灵活,xml确实比较麻烦。


4. 使用JavaConfig定义bean的具体实例

光说不练那是假把式,必须得有实例。但是前提是兄弟们咱已经把事情的来龙去脉说清楚了,要是不知道为何而来从何而去,比较容易混淆概念,从而容易懵圈。


说实话我Spring写了很久了,还搞不清楚这三种方式的区别,后来是靠着我强悍的大脑的超强理解能力才分清楚的(请原谅我无脑的对自己的吹捧,朋友们我就是这么一个人,非常完美吭)。


话不多少,酒不多喝,实例走起!


4.1 来个普普通通的类

普普通通,毫无污染的普通Java类一个,供您鉴赏。


package org.maoge.javaconfigbean;

public class Singer {

private String name;

public void sing() {

 System.out.println("歌手[" + name + "]开唱啦,快挥舞起你手中的荧光棒吧");

}

public String getName() {

 return name;

}

public void setName(String name) {

 this.name = name;

}

}



4.2 来个普普通通的方法返回我们想要的对象

我们定义两个方法,返回我们想要的对象,这两个方法到目前为止是再普通不过的普通方法。


package org.maoge.javaconfigbean;

public class BeanConfiguration {

/**

 * 返回歌手周杰伦

 */

public Singer zhoujielun() {

 Singer singer = new Singer();

 singer.setName("周杰伦");

 return singer;

}

/**

 * 返回歌手林俊杰

 */

public Singer linjunjie() {

 Singer singer = new Singer();

 singer.setName("林俊杰");

 return singer;

}

}


4.3 添加@bean注解,使方法的返回值成为bean

通过在方法上添加@bean注解,Spring容器会将方法的返回值作为bean放入容器中,而bean的名字就是方法的名字。


package org.maoge.javaconfigbean;

import org.springframework.context.annotation.Bean;

public class BeanConfiguration {

/**

 * 返回歌手周杰伦 通过@Bean告知容器,将该方法的返回值作为bean放入容器中管理

 */

@Bean

public Singer zhoujielun() {

 Singer singer = new Singer();

 singer.setName("周杰伦");

 return singer;

}

/**

 * 返回歌手林俊杰 通过@Bean告知容器,将该方法的返回值作为bean放入容器中管理

 */

@Bean

public Singer linjunjie() {

 Singer singer = new Singer();

 singer.setName("林俊杰");

 return singer;

}

}


4.4 添加@Configuration注解启用配置

在之前讲述使用注解定义bean时,我们有一个xml配置context:component-scan,用来扫描指定的包下面的bean。


在使用JavaConfig定义bean是也类似,我们需要在类上添加注解@Configuration,来告诉Spring,该类是一个配置类,里面可能包含bean的定义,请扫描我。具体代码如下:


package org.maoge.javaconfigbean;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

/**

* 通过@Configuration告诉Spring,本类是一个配置类,请扫描本类中的bean

*/

@Configuration

public class BeanConfiguration {

/**

 * 返回歌手周杰伦

 */

@Bean

public Singer zhoujielun() {

 Singer singer = new Singer();

 singer.setName("周杰伦");

 return singer;

}

/**

 * 返回歌手林俊杰

 */

@Bean

public Singer linjunjie() {

 Singer singer = new Singer();

 singer.setName("林俊杰");

 return singer;

}

}


4.5 测试运行

这一步就很简单了,先通过配置类获取容器对象,然后从容器中获取定义的bean,然后运行bean的方法。


注意AnnotationConfigApplicationContext也好理解,就是Spring给我们封装好的类,它可以读取类中注解的配置信息(此处读取BeanConfiguration.class),然后根据配置信息为我们生成容器,我们直接调用就行。


package org.maoge.javaconfigbean;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class JavaConfigContainerDemo {

public static void main(String[] args) {

 //通过BeanConfiguration.class获取对Spring容器的配置信息,然后返回context指向容器

 AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(BeanConfiguration.class);

 //从容器中获取对象

 Singer zhoujielun=(Singer) context.getBean("zhoujielun");

 zhoujielun.sing();

 //从容器中获取对象

 Singer linjunjie=(Singer) context.getBean("linjunjie");

 linjunjie.sing();

}

}


5. 总结

Spring提供了三种定义bean的方式,就好比我们生活中出行可以采用高铁、飞机、汽车、自行车、走路一样的道理,更加方便,可以根据实际情况灵活选用。


但是目的相同,都是为了给Spring容器提供配置信息,主要就是bean的定义信息。


后续我这边尽可能的对实例提供多种配置方法实现,以便于大家理解,我这边麻烦就麻烦点,但是要让大家感觉舒爽啊,哈哈!

上一篇:API —— 这是一个新的战场


下一篇:Spring Bean的生命周期管理(下)