配置元数据就是我们如何装配bean。我们在描述如何装配bean的时候,spring非常的灵活,它提供了三种主要的装配机制:
一、在xml中进行显示的配置
1、新建一个POJO类
public class BMWCar implements Car {
@Override
public String getName() {
return "宝马汽车";
}
}
2、创建一个配置文件,这里我们使用xml作为配置文件
<?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">
<bean id="bMWCar" class="cn.szyrm.pojo.BMWCar"></bean>
</beans>
3、使用容器XmlBeanFactory
package cn.szyrm.beanFactory;
import cn.szyrm.pojo.Car;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
public class XmlBeanFactoryTest {
public static void main(String[] args) {
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("xmlBeanFactoryTest.xml"));
Car bMWCar = beanFactory.getBean("bMWCar", Car.class);
System.out.println(bMWCar.getName());
}
}
4、测试
运行main方法,然后我们可以发现在控制台有如下输出
23:16:09.728 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 2 bean definitions from class path resource [xmlBeanFactoryTest.xml]
23:16:09.732 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanFactory - Creating shared instance of singleton bean 'bMWCar'
宝马汽车
这里我们简单的演示了下BeanFactory的用法,在实际的生产环境中几乎不会使用BeanFactroy。而是使用其子接口ApplicationContext来做为Spring的容器。通过这个简单的例子和 spring 容器图 一起理解。这段代码的核心原理无非就是:
- 1、XmlBeanFactory通过读取配置文件
xmlBeanFactoryTest.xml
- 2、通过xml文件中配置类并通过发射将类进行示例化
- 3、将实例化话后对象存储在某个地方( 可能是map对象中)
- 4、通过getBean方法从容器中将之前已经实例化好的对象取出
- 5、调用实例化好的对象
二、在java中进行显示的配置
1、POJO还是使用上面的BMWCar
2、配置文件,这里采用基于Java的配置方式
import cn.szyrm.pojo.BMWCar;
import cn.szyrm.pojo.Car;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@Bean
public Car bMwCar(){
return new BMWCar();
}
}
3、使用AnnotationConfigApplicationContext
来读取配置类AppConfig
import cn.szyrm.pojo.Car;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class ApplicationContextTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
Car car = applicationContext.getBean(Car.class);
System.out.println(car.getName());
}
}
4、测试
运行main方法,我们会发现有如下的输出
23:47:16.699 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@1786dec2
23:47:16.713 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor'
23:47:16.820 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor'
23:47:16.821 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory'
23:47:16.822 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'
23:47:16.823 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor'
23:47:16.830 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'appConfig'
23:47:16.833 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bMwCar'
宝马汽车
三、隐式的bean发现和自动装配
spring是通过两个角度来实现自动化装配的:
- 1、组件扫描:spring会自动的发现应用上下文中所创建的bean.
- 2、自动装配:spring自动满足bean之间的依赖
新建一个可被发现的bean
package cn.szyrm.pojo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class BenzCar implements Car {
@Autowired
private Engine engine;
@Override
public String getName() {
return "奔驰汽车" ;
}
@Override
public void start() {
engine.start();
}
}
import org.springframework.stereotype.Component;
@Component
public class DCTEngine implements Engine{
@Override
public void start() {
System.out.println("双离合发动机启动");
}
}
这里我们注意到,POJO类BenzCar
、DCTEngine
上添加了一个@Component注解,这个就是告诉spring 当前类应该被当成一个bean来处理。
- 在配置类上设置包扫描的路径
@Configuration
@ComponentScan("cn.szyrm.pojo")
public class AppConfig {
}
- 初始容器
/**
* 测试spring 的组件扫描及自动注入
*/
public class ComponentScanTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
Car car = applicationContext.getBean("benzCar",Car.class);
car.start();
}
}
- 测试使用
Connected to the target VM, address: '127.0.0.1:51781', transport: 'socket'
08:01:07.281 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@1786dec2
08:01:07.293 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor'
08:01:07.341 [main] DEBUG org.springframework.context.annotation.ClassPathBeanDefinitionScanner - Identified candidate component class: file [D:\learn\java\spring-source-learn\target\classes\cn\szyrm\pojo\BenzCar.class]
08:01:07.342 [main] DEBUG org.springframework.context.annotation.ClassPathBeanDefinitionScanner - Identified candidate component class: file [D:\learn\java\spring-source-learn\target\classes\cn\szyrm\pojo\DCTEngine.class]
08:01:07.426 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor'
08:01:07.427 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory'
08:01:07.428 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'
08:01:07.429 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor'
08:01:07.435 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'appConfig'
08:01:07.439 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'benzCar'
08:01:07.445 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'DCTEngine'
08:01:07.446 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bMwCar'
双离合发动机启动
上面是我们经常用到的三种配置方式,此外我们还可以通过@Import注解进入Bean的导入
四、通过@Import配置Bean
import的注解源码如下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
/**
* {@link Configuration @Configuration}, {@link ImportSelector},
* {@link ImportBeanDefinitionRegistrar}, or regular component classes to import.
*/
Class<?>[] value();
}
通过注释,我们可以知道我们可以配置一个普通的类,可以配置实现了ImportSelector
接口的类以及配置实现ImportBeanDefinitionRegistrar
接口的类。那么我们来试试每个配置的用法:
1、常规的Bean
package cn.szyrm.applicationContext;
/**
* 用来测试通过@Import配置为spring bean。
* 不实现任何特定的接口,即一个POJO对象
*/
public class RegularBean {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void say(){
System.out.println("I'm a regular bean ");
}
}
2、实现了ImportSelector
接口的类
package cn.szyrm.applicationContext;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
public class ImportSelectorBean implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{ChooseByImportSelector.class.getName()};
}
}
package cn.szyrm.applicationContext;
/**
* 通过被实现ImportSelector返回进行配置的bean
*/
public class ChooseByImportSelector {
private String name;
public void say(){
System.out.println("I'm Choose By ImportSelector");
}
}
3、实现了ImportBeanDefinitionRegistrar
接口的类
package cn.szyrm.applicationContext;
import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
public class ImportBeanDefinitionRegistrarBean implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
registry.registerBeanDefinition("testImportBeanDefinitionRegistrar",new AnnotatedGenericBeanDefinition(TestImportBeanDefinitionRegistrar.class));
}
}
package cn.szyrm.applicationContext;
/**
* 这个类用来测试通过实现了 ImportBeanDefinitionRegistrar 接口的类导入Bean
*/
public class TestImportBeanDefinitionRegistrar {
}
4、配置类如下:
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
@Import({RegularBean.class, ImportSelectorBean.class,ImportBeanDefinitionRegistrarBean.class})
public class AppConfig {
}
5、测试用的相关类
public class ImportDemo {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
PrintUtil.printBeanDefinition(applicationContext);
}
}
import org.springframework.context.ApplicationContext;
import java.util.stream.Stream;
public class PrintUtil {
public static void printBeanDefinition(ApplicationContext applicationContext){
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
Stream.of(beanDefinitionNames).forEach(System.out::println);
}
}
6、运行测试类,发现输出如下:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
appConfig
cn.szyrm.applicationContext.RegularBean
cn.szyrm.applicationContext.ChooseByImportSelector
testImportBeanDefinitionRegistrar
可以看到我们三种配置都已经生效
五、在javaconfig中引入xml配置
如果之前的项目上的主要配置是基于xml的,我们想在基于注解的配置spring项目中如何引入这些配置呢?请看下面的示例:
1、xml配置文件如下:
<?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">
<bean id="bMWCar" class="cn.szyrm.pojo.BMWCar"></bean>
<bean id="BenzCar" class="cn.szyrm.pojo.BenzCar"></bean>
</beans>
2、java配置类如下:
import org.springframework.context.annotation.*;
@Configuration
@ImportResource("classpath:xmlBeanFactoryTest.xml")
public class AppConfig {
}
3、测试类如下:
package cn.szyrm.applicationContext;
import cn.szyrm.PrintUtil;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class JavaConfigImportXmlTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
PrintUtil.printBeanDefinition(context);
}
}
4、打印出来的bean的名称如下:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
appConfig
bMWCar
BenzCar
通过上面的输出,我们可以看到。通过java config配置类已经可以导入xml文件实验成功。