spring自动配置的原理
要点在于理解@Import和@Conditional注解的作用
@Import导入对象的三种方式
- 如何从spring容器中获取,通过@Import方式导入的其实和下面的原理是一样的,都是直接从spring容器中获取,只不过@Import不需要扫描
回忆Spring中如何从容器中获取对象
- 点击redisTemplate注入的位置左边的小图标,跳转到注入的位置RedisAutoConfiguration配置类
- ctrl+H查看类的所有子接口以及实现类
启动类中的方法取出的就是容器,ConfigurableApplicationContext context = SpringApplication.run(Springboot03ImportAnnApplication.class, args);
public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable
查看ClassPathXmlApplicationContext的UML图,使用alt+鼠标可以放大
- ClassPathXmlApplicationContext和ConfigurableApplicationContext都是spring容器的实现类实现类,以下为ClassPathXmlApplicationContext类图
- 第二种:导入一个配置类,配置类中@Bean,会自动的批量导入对象
/**
* @ComponentScan("com.itheima") 注解作用:组件扫描,扫描指定包下的所有注解,注入对象到spring的ioc容器
* @Import(JdbcConfiguration.class) 注解作用:导入配置类
* @EnableTransactionManagement 注解作用:开启事务管理器
*/
@Configuration
@Import(JdbcConfiguration.class)//导入本项目中的配置类
public class SpringConfiguration {
@Bean
public UserService getUserService(){
return new UserServiceImpl();
}
}
- 导入SelectImport接口的实现类对象,把批量的类全限定名称的类,注入到ioc容器 @Import(MySelectImport.class)
public class MySelectImport implements ImportSelector {
//返回所有需要导入到spirng容器中的字节码文件,这些类的字节码文件将被注入到spring容器中
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
String[] clazzs = {
"com.ahu.springboot03_import_ann.service.UserServiceImpl",
"com.ahu.springboot03_import_ann.pojo.User"
};
return clazzs;
}
}
@Configuration条件注解
**思考一个问如果springboot在初始化的时候把spring.factories中的配置类全部加载一遍,那电脑就炸了,所以需要控制配置类的加载
- @Configuration表示当前的类是一个注解类
- RedisAutoConfiguration中@ConditionalOnClass({RedisOperations.class}),当前的classpath路径下存在RedisOperations的类对象的时候其他的注解有效
- 查看源码可以知道,可以作用在类和方法上面
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional({OnClassCondition.class})
public @interface ConditionalOnClass {
Class<?>[] value() default {};
String[] name() default {};
}
小案例
- @ConditionalOnClass classpath下存在这个类的时候生效
- @ConditionalOnProperty 注解作用:当配置文件application.properties中存在key配置且值为true时,条件生效
- name 属性名
- havingValue 设置配置的默认值
- matchIfMissing 设置value是匹配的值,如果匹配条件生效,如果不匹配则不生效
@Configuration
public class SpringConfiguration {
/**
* @ConditionalOnClass classpath下存在这个类的时候生效
* @ConditionalOnProperty 注解作用:当配置文件application.properties中存在key配置且值为true时,条件生效
* name 属性名 ,havingValue 设置配置的默认值 , matchIfMissing 设置value匹配的值,如果匹配条件生效,如果不匹配则不生效
* @return
*/
@Bean
// @ConditionalOnClass(name = "com.ahu.springboot_conditional_ann.pojo.Cat")
@ConditionalOnProperty(name = "com.ahu.condition", havingValue = "true", matchIfMissing = true)
public Dog getDog(){
return new Dog();
}
}
@SpringBootApplication
public class SpringbootConditionalAnnApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringbootConditionalAnnApplication.class, args);
Dog dog = context.getBean(Dog.class);
System.out.println(dog);
}
}
查看springboot中redis的配置类源码学习如何使用注解
点击配置文件中的spring.redis.port跳转RedisProperties.class中,查看通过@ConfigurationProperties注入
@ConfigurationProperties(
prefix = "spring.redis"
)
那么springboot自动配置跟上面知识点有什么关联呢?
- 查看注解@SpringBootApplication
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
- 查看注解@EnableAutoConfiguration,含有注解@Import({AutoConfigurationImportSelector.class}),AutoConfigurationImportSelector是SelectImport接口的实现类,只不过它导入的是spring.factories中的配置类