Spring 是一个轻量级、非入侵式的控制反转 (IoC) 和面向切面 (AOP) 的框架
一、spring注入方式选择
1、属性注入
@Service
public class AService {
@Autowired
BService bService;
}
属性注入限制:类只能在IOC容器中使用,对于IOC容器以外的环境,除了使用反射获取依赖之外,无法复用该实现类
2、SET方法注入
@Service
public class AService {
BService bService;
@Autowired
public void setbService(BService bService) {
this.bService = bService;
}
}
Spring3.0 文档中,官方提倡 set 方法注入,说构造方法注入属性太多可能会让代码变得非常臃肿
3、构造方法注入
@Service
public class AService {
BService bService;
@Autowired
public AService(BService bService) {
this.bService = bService;
}
}
Spring4.x 开始,官方推荐通过构造方法注入的方式,能够保证注入的组件不可变,并且能够确保需要的依赖不为空
优点:
1、依赖不可变:对象创建后无法再通过set方法等改变
2、依赖不为空:自动检查注入对象不为空才注入成功
3、完全初始化:获取依赖对象已经初始化了,拿到的对象已经初始化
二、spring容器注入bean方式
1、@Configuration + @Bean
1.1、@Configuration声明配置类, @Bean 注解加入容器
2、@Componet + @ComponentScan
2.1、@Componet声明组件类
2.2、@ComponentScan扫描注入spring容器
3、@Import注解导入
3.1、@Import导入需要注入到容器类
3.2、@Import + ImportSelector:自定义ImportSelector,重写selectImports 方法将注入spring容器的bean全量名
3.3 @Import + ImportBeanDefinitionRegistrar
3.4 @Import + DeferredImportSelector
4、使用FactoryBean接口
5、使用 BeanDefinitionRegistryPostProcessor
Spring容器启动执行 BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry 方法,通过手动向beanDefinitionRegistry中注册了person的BeanDefinition,将Person对象管理到Spring容器中
三、ApplicationRunner、CommandLineRunner、InitializingBean、@PostConstruct 执行顺序
3.1、CommandLineRunner和ApplicationRunner的作用相同,入参不同
3.2、InitializingBean为bean提供了初始化方法的方式,afterPropertiesSet方法
@PostConstruct>InitializingBean>ApplicationRunner>CommandLineRunner
三、springboot运行jar包
1、springboot提供插件spring-boot-maven-plugin把程序打包成一个可执行jar包:project-name.jar
<build> <finalName>project-name</finalName> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin </artifactId> </plugin> </plugins> </build>
2、project-name.jar结构
2.1、META-INF程序入口:pom文件、MAINIFEST.MF jar包信息
Main-Class是org.springframework.boot.loader.JarLauncher,当我们使用java -jar project-name.jar 调用JarLauncher的main方法,而不是我们编写的SpringApplication。
SpringBoot内部提供SpringBootLoader用于执行SpringApplication工具类
2.2、BOOT-INF:资源文件、依赖包
2.3、org.springframework.boot.laoder:SpringBootLoader代码
Launcher:基础抽象类:JarLauncher、WarLuncher、PropertiesLauncher
Archive:归档文件的基础抽象类,
JarFileArchive implements Archive:包文件(getUrl、getManifest):内部依赖的jar对应的URL,会使用 !/ 分隔开的协议,SpringBoot 使用org.springframework.boot.loader.jar.Handler处理这些URL
ExplodedArchive implements Archive:文件目录的抽象
JarFile:jar包的封装。JarFileArchive构造方法new JarFile(file)
3、执行过程
3.1、JarLauncher构造调用父类ExecutableArchiveLauncher构造方法
3.2、JarLauncher启动入库:构造JarLauncher调用launch方法(参数传递)
3.3、ExecutableArchiveLauncher实现Launcher类执行launch方法
getClassPathArchives方法在会去找lib目录下对应的依赖JarFileArchive,同时项目自身的JarFileArchive
LaunchedURLClassLoader类加载器的父类加载器是当前执行类JarLauncher的类加载器
getMainClass方法会去项目自身的Archive中的Manifest中找出key为Start-Class的类
4、MainMethodRunner的run方法
SpringBoot在可执行jar包中定义了自己的一套规则,比如第三方依赖jar包在/lib目录下,jar包的URL路径使用自定义的规则并且这个规则需要使用org.springframework.boot.loader.jar.Handler处理器处理。它的Main-Class使用JarLauncher,如果是war包,使用WarLauncher执行。这些Launcher内部都会另起一个线程启动自定义的SpringApplication类。
这些特性通过spring-boot-maven-plugin插件打包完成。