IOC加载原理
类 -> BeanDefinition -> BeanFactory -> Bean
1、基于配置文件
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
2、基于配置类
ApplicationContext ac = new AnnotationConfigApplicationContext(JavaConfig.class);
JavaConfigApplication.java
用@Configuration
注解修饰,表示Java配置类,用@Bean
修饰的方法,返回的结果在系统启动时会被装配到IOC容器里面。
public class User {
}
@Configuration
public class JavaConfigApplication {
@Bean
public User getUser() {
return new User();
}
public static void main(String[] args) {
ApplicationContext ac = new AnnotationConfigApplicationContext(JavaConfigApplication.class);
System.out.println(ac.getBean(User.class));
}
}
或者在要加在的类名上加上@Component
注解,在JavaConfigApplication.java
增加@ComponentScan
注解。这种方式启动会慢些。
@Component
public class User {
}
@Configuration
@ComponentScan
public class JavaConfigApplication {
public static void main(String[] args) {
ApplicationContext ac = new AnnotationConfigApplicationContext(JavaConfigApplication.class);
System.out.println(ac.getBean(User.class));
}
}
3、springboot启动
SpringApplication.run(Application.class, args);
其中Application类用@SpringBootApplication
注解。
@ComponentScan注解
扫描启动器所在的包及其子包带有指定注解的类自动装配到bean容器里。会被自动装配的注解包括@Controller、@Service、@Component、@Repository等等。
@SpringBootConfiguration注解
与@Configuration
注解等价,所以在启动类中用@Bean
修饰的方法,返回的对象也是会被注入到IOC容器里。其中利用反射的原理生成对象。
@EnableAutoConfiguration注解,重点研究
EnableAutoConfiguration注解源码:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
AutoConfigurationPackage注解源码:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
}
@Import注解
通过快速导入的方式实现把实例加入spring的IOC容器中。场景:@SpringBootApplication
注解只会扫描当前类路径下的类,当引用第三方包时,需要加载第三方类实例时,可以用@Import
导入。
在Spring中我们将对象添加到IOC容器中的方式有哪些:
- 包扫描+组件标注注解(@Controller/@Service/@Repository/@Component)[自己写的类]
- @Bean、
[导入的第三方包里面的组件] - 实现FactoryBean接口, 实现getObject方法,用@Component注入,可以动态注入,例如Mybatis
- @Import注解,快速给容器中导入一个组件
@Import三种用法
1、直接填class数组,静态导入
@Import({Registrar.class})
2、ImportSelector方式。返回需要导入的组件的全类名数组
实现ImportSelector接口,重写selectImports
方法,不是把AutoConfigurationImportSelector导入到容器里,而是把selectImports
返回结果导入到容器。
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// 全类路径
return new String[]{User.class.getName()};
}
}
3、ImportBeanDefinitionRegistrar方式,手动注册bean到容器中
导入的是实现了ImportBeanDefinitionRegistrar
接口的类型。
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
RootBeanDefinition user = new RootBeanDefinition(User.class);
beanDefinitionRegistry.registerBeanDefinition("user", user);
}
}
spring.factories文件
加载META-INF/spring.factories
文件里的自动配置类。
org.springframework.boot.autoconfigure.EnableAutoConfiguration
所以加了@EnableAutoConfiguration
注解后,在容器启动后,会自动扫描各个依赖包里面META-INF/spring.factories
文件里的自动配置类。如果想要注入自定义第三方依赖,则需要再自定义包创建META-INF/spring.factories
文件,在配置文件里配置org.springframework.boot.autoconfigure.EnableAutoConfiguration
,值为Java配置类全路径,在Java配置类需要增加@ComponentScan
注解,这就可以注入其它Bean。
@Conditional条件注解
按照一定的条件进行判断,满足条件给容器注册bean。例如Mybatis会使用@ConditionalOnProperty
注解,判断是否配置spring.datasource.type
信息,如果没有配置,则不会创建dataSource
实例。
/META-INF/spring-autoconfigure-metadata.properties
文件可以配置条件注入。例如Mybatis依赖iBatis,在mybatis-starter包有这样的配置:
com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration.ConditionalOnClass=org.apache.ibatis.session.SqlSessionFactory,org.mybatis.spring.SqlSessionFactoryBean