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的定义信息。
后续我这边尽可能的对实例提供多种配置方法实现,以便于大家理解,我这边麻烦就麻烦点,但是要让大家感觉舒爽啊,哈哈!