Spring注解驱动开发第2讲——使用@Configuration和@Bean给容器中注册组件
写在前面
在以前学习Spring的过程中,我们是通过编写XML配置文件来定义我们的Bean的,这种编写XML配置文件的方式不仅繁琐,而且还很容易出错,稍有不慎就会导致编写的应用程序各种报错,排查半天,发现是XML文件配置不对!另外,每个项目都编写大量的XML文件来配置Spring,也大大增加了项目维护的复杂度,往往很多个项目的Spring XML文件的配置大部分是相同的,只有很少量的配置不同,这也造成了配置文件上的冗余。
而要是使用了Spring注解驱动来开发,你会发现以上这些问题都将不存在了。整个世界都变得清静了,于是你不由得会心一笑????!这也导致了学习Spring注解驱动开发是一件多么迫不急待地事,正如教员说的那句话:
多少事,从来急。天地转,光阴迫。一万年太久,只争朝夕!
我喜欢教员!毛选第一卷还看了一大部分。我还非常喜欢国际歌,特别喜欢第六段:
是谁创造了人类世界?
是我们劳动群众!
一切归劳动者所有,
哪能容得寄生虫?
最可恨那些毒蛇猛兽,
吃尽了我们的血肉!
一旦把它们消灭干净,
鲜红的太阳照遍全球!
鲜红的太阳必将照遍全球!!!
Spring IOC和DI
在Spring容器的底层,最重要的功能就是IOC和DI,也就是控制反转和依赖注入。
DI和IOC它俩之间的关系是DI不能单独存在,DI需要在IOC的基础上来完成。
在Spring内部,所有的组件都会放到IOC容器中,组件之间的关系通过IOC容器来自动装配,也就是我们所说的依赖注入。接下来,我们就使用注解的方式来完成容器中组件的注册、管理及依赖、注入等功能。
在介绍使用注解完成容器中组件的注册、管理及依赖、注入等功能之前,我们先来看看使用XML配置文件是如何注入Bean的。
通过XML配置文件注入JavaBean
首先,新建一个maven项目,例如spring-annotation-liayun,注意其打包方式是jar。
这个时候我们发现新建的maven项目的编译版本是1.5。那这还玩个毛啊!要知道现在都2020年末了,都快出Java 16这个版本了,但为了稳定,公司里面现在普遍使用的都是Java 8,所以在这里我们需要设置编译版本为1.8,即在pom文件中添加maven插件指定编译时候使用的JDK版本。
<build>
<plugins>
<!-- java编译插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
以上只是调整局部JDK版本。这时,你会发现新建的maven项目依然会报错,如下图所示。
这个报错你也不用担心,因为有时候加依赖或者插件,maven项目就会报错。这时,就需要时不时地Update一下项目了,Update项目之后,你就会发现项目的编译版本为1.8了,如下图所示。
然后,在pom文件中添加对Spring的依赖,注意咱们在这儿使用的Spring是4.3.12.RELEASE
这个版本的。
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
</dependencies>
接着,在工程的com.meimeixia.bean包下创建一个Person类,作为测试的JavaBean,代码如下所示。
package com.meimeixia.bean;
public class Person {
private String name;
private Integer age;
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 Person(String name, Integer age) {
super();
this.name = name;
this.age = age;
}
public Person() {
super();
// TODO Auto-generated constructor stub
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
紧接着,在工程的src/main/resources目录下创建Spring的配置文件,例如beans.xml,通过该配置文件将Person类注入到Spring的IOC容器中,该配置文件中的内容如下所示。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
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-4.2.xsd">
<!-- 注册组件 -->
<bean id="person" class="com.meimeixia.bean.Person">
<property name="age" value="18"></property>
<property name="name" value="liayun"></property>
</bean>
</beans>
至此,我们使用XML配置文件的方式注入JavaBean就完成了。
接下来,我们在工程的com.meimeixia包下创建一个MainTest类来进行测试,该类的代码如下所示。
package com.meimeixia;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.meimeixia.bean.Person;
public class MainTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
Person person = (Person) applicationContext.getBean("person");
System.out.println(person);
}
}
运行以上main方法,输出的结果信息如下图所示。
从输出结果中,我们可以看出,Person类通过beans.xml文件的配置,已经注入到Spring的IOC容器中去了。
通过注解注入JavaBean
通过XML配置文件的方式,我们可以将JavaBean注入到Spring的IOC容器中。那使用注解又该如何实现呢?别急,其实使用注解比使用XML配置文件要简单的多,我们在项目的com.meimeixia.config包下创建一个MainConfig类,并在该类上添加@Configuration注解来标注该类是一个Spring的配置类,也就是告诉Spring它是一个配置类,最后通过@Bean注解将Person类注入到Spring的IOC容器中。
package com.meimeixia.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.meimeixia.bean.Person;
/**
* 以前配置文件的方式被替换成了配置类,即配置类==配置文件
* @author liayun
*
*/
// 这个配置类也是一个组件
@Configuration // 告诉Spring这是一个配置类
public class MainConfig {
// @Bean注解是给IOC容器中注册一个Bean,类型自然就是返回值的类型,id默认是用方法名作为id
@Bean
public Person person() {
return new Person("liayun", 20);
}
}
没错,通过MainConfig类我们就能够将Person类注入到Spring的IOC容器中,是不是很Nice啊!!主要是我们在类上加上@Configuration注解,并在方法上加上@Bean注解,就能够将方法中创建的JavaBean注入到Spring的IOC容器中。
然后,我们修改MainTest类中的main方法,以测试通过注解注入的Person类,如下所示。
package com.meimeixia;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.meimeixia.bean.Person;
import com.meimeixia.config.MainConfig;
public class MainTest {
public static void main(String[] args) {
// ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
// Person person = (Person) applicationContext.getBean("person");
// System.out.println(person);
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
Person person = applicationContext.getBean(Person.class);
System.out.println(person);
}
}
再次运行以上main方法,输出的结果信息如下图所示。
可以看出,通过注解将Person类注入到了Spring的IOC容器中。
到这里,我们已经明确了,通过XML配置文件和注解这两种方式都可以将JavaBean注入到Spring的IOC容器中。那么,使用注解将JavaBean注入到IOC容器中时,使用的bean的名称又是什么呢?我们可以在MainTest类的main方法中添加如下代码来获取Person这个类型的组件在IOC容器中的名字。
// Person这个类型的组件在IOC容器中的名字是什么呢?
String[] namesForType = applicationContext.getBeanNamesForType(Person.class);
for (String name : namesForType) {
System.out.println(name);
}
这样,MainTest类的main方法的完整代码如下所示。
package com.meimeixia;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.meimeixia.bean.Person;
import com.meimeixia.config.MainConfig;
public class MainTest {
public static void main(String[] args) {
// ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
// Person person = (Person) applicationContext.getBean("person");
// System.out.println(person);
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
Person person = applicationContext.getBean(Person.class);
System.out.println(person);
// Person这个类型的组件在IOC容器中的名字是什么呢?
String[] namesForType = applicationContext.getBeanNamesForType(Person.class);
for (String name : namesForType) {
System.out.println(name);
}
}
}
运行以上main方法之后,输出的结果信息如下图所示。
那这里打印出的person到底是啥呢?我们修改下MainConfig类中的person()方法,将其名字修改成person01,如下所示。
package com.meimeixia.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.meimeixia.bean.Person;
/**
* 以前配置文件的方式被替换成了配置类,即配置类==配置文件
* @author liayun
*
*/
// 这个配置类也是一个组件
@Configuration // 告诉Spring这是一个配置类
public class MainConfig {
// @Bean注解是给IOC容器中注册一个Bean,类型自然就是返回值的类型,id默认是用方法名作为id
@Bean
public Person person01() {
return new Person("liayun", 20);
}
}
此时,我们再次运行MainTest类中的main方法,输出的结果信息如下图所示。
看到这里,大家应该有种豁然开朗的感觉了,没错!!使用注解注入JavaBean时,Bean在IOC容器中的名称就是使用@Bean注解标注的方法名称。我们可不可以为Bean单独指定名称呢?那必须可以啊!只要在@Bean注解中明确指定名称就可以了。比如在下面MainConfig类的代码中,我们将person01()方法上的@Bean注解修改成了@Bean(“person”)注解,如下所示。
package com.meimeixia.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.meimeixia.bean.Person;
/**
* 以前配置文件的方式被替换成了配置类,即配置类==配置文件
* @author liayun
*
*/
// 这个配置类也是一个组件
@Configuration // 告诉Spring这是一个配置类
public class MainConfig {
// @Bean注解是给IOC容器中注册一个Bean,类型自然就是返回值的类型,id默认是用方法名作为id
@Bean("person")
public Person person01() {
return new Person("liayun", 20);
}
}
此时,我们再次运行MainTest类中的main方法,输出的结果信息如下图所示。
可以看到,此时,输出的JavaBean的名称确实是person了。
小结
我们在使用注解方式向Spring的IOC容器中注入JavaBean时,如果没有在@Bean注解中明确指定Bean的名称,那么就会使用当前方法的名称来作为Bean的名称;如果在@Bean注解中明确指定了Bean的名称,那么就会使用@Bean注解中指定的名称来作为Bean的名称。