javaSpringbootWeb--原理
2023-12-20 07:20:13
配置优先级
- 文件配置
命令行 > java系统属性 >properties > yml > yaml - java系统属性
-Dserver.port = 9000
- 命令行参数
--server.port = 9001
Bean 管理
- 获取bean
@Autowired
private ApplicationContext applicationContext; //IOC容器对象
@Test
void testGetBean(){
//根据bean名称获取
EmpController bean1 = (EmpController) applicationContext.getBean("eptController");
//根据bean的类型获取
EmpController bean2 = applicationContext.getBean(EmpController.class);
//根据bean的名称和类型获取
EmpController bean3 = applicationContext.getBean("eptController", EmpController.class);
}
Bean 作用域
- singleton 容器内同 名称的 bean 只有一个实例 (单例) (默认)
- prototype 每次使用该 bean 时会创建新的实例 (非单例)
- request 每个请求范围内会创建新的实例(web环境中,了解)
- session 每个会话范围内会创建新的实例 (web环境中,了解)
- application 每个应用范围内会创建新的实例 (web环境中,了解)
配置Bean的作用域
@Scope(“prototype”) 非单例
@Lazy 延迟初始化 ,第一次使用时再初始化。
第三方Bean @Bean
通过@Bean注解的name/value属性指定bean名称,如果未指定,默认是方法名
@Component 及衍生注解与 @Bean注解使用场景?
- 项目中自定义的,使用@Component及其衍生注解
- 项目中引入第三方的,使用@Bean注解
Springboot原理
起步依赖原理
依赖传递
自动配置
SpringBoot的自动配置就是当spring容器启动后,一些配置类、bean对象就自动存入到了IOC容器中,不需要我们手动去声明,从而简化了开发,省去了繁琐的配置操作。
自动配置原理
方案一: @ComponentScan 组件扫描
方案二: @lmport导入。使用@lmport导入的类会被Spring加载到10C容器中,导入形式主要有以 下几种:
- 导入普通类
- 导入配置类
- 导入 ImportSelector 接口实现类
- @EnableXxxx注解,封装@Import注解
源码跟踪
@SpringBootApplication
@Target({ElementType.TYPE}) //元注解
@Retention(RetentionPolicy.RUNTIME) //元注解
@Documented//元注解
@Inherited//元注解
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
@AliasFor(
annotation = EnableAutoConfiguration.class
)
Class<?>[] exclude() default {};
@AliasFor(
annotation = EnableAutoConfiguration.class
)
String[] excludeName() default {};
@AliasFor(
annotation = ComponentScan.class,
attribute = "basePackages"
)
String[] scanBasePackages() default {};
@AliasFor(
annotation = ComponentScan.class,
attribute = "basePackageClasses"
)
Class<?>[] scanBasePackageClasses() default {};
@AliasFor(
annotation = ComponentScan.class,
attribute = "nameGenerator"
)
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
@AliasFor(
annotation = Configuration.class
)
boolean proxyBeanMethods() default true;
}
@SpringBootConfiguration // 当前类是一个配置类,可以在@SpringBootApplication中声明第三方bean(@Bean)
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration //声明配置类
@Indexed //加速应用启动
public @interface SpringBootConfiguration {
@AliasFor(
annotation = Configuration.class
)
boolean proxyBeanMethods() default true;
}
@ComponentScan //组件扫描
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
@EnableAutoConfiguration//底层通过import导入类或者配置类
@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 {};
}
//AutoConfigurationImportSelector
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered
// DeferredImportSelector
public interface DeferredImportSelector extends ImportSelector
// ImportSelector
public interface ImportSelector {
String[] selectImports(AnnotationMetadata importingClassMetadata); //类的全类名
@Nullable
default Predicate<String> getExclusionFilter() {
return null;
}
}
//AutoConfigurationImportSelector 中的selectImports
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}
//getAutoConfigurationEntry
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
configurations = this.removeDuplicates(configurations);
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = this.getConfigurationClassFilter().filter(configurations);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
}
}
// configurations
//List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = new ArrayList(SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader()));
ImportCandidates.load(AutoConfiguration.class, this.getBeanClassLoader()).forEach(configurations::add);
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you are using a custom packaging, make sure that file is correct.");
return configurations;
}
//META-INF/spring.factories
//META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports.
选中双击shift
@AutoConfiguration
@ConditionalOnClass({Gson.class})
@EnableConfigurationProperties({GsonProperties.class})
public class GsonAutoConfiguration {}
//AutoConfiguration
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration(
proxyBeanMethods = false
) //配置类
@AutoConfigureBefore
@AutoConfigureAfter
public @interface AutoConfiguration {
//GsonAutoConfiguration
@Bean //可以使用Autowired注入
@ConditionalOnMissingBean
public Gson gson(GsonBuilder gsonBuilder) {
return gsonBuilder.create();
}
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports.中的配置类不是全部注册为IOC容器的bean,而是会根据@ConditionalOnMissingBean按条件装配
条件装配注解 @Conditional
- 作用:按照一定的条件进行判断,在满足给定条件后才会注册对应的bean对象到SpringIOC容器中
- 位置:方法、类
- @Conditional 本身是一个父注解,派生出大量的子注解!
- @ConditionalOnClass: 判断环境中是否有对应字节码文件,才注册bean到IOC容器。
- @ConditionalOnMissingBean: 判断环境中没有对应的bean (类型或名称),才注册bean到IOC容器
- @ConditionalOnProperty: 判断配置文件中有对应属性和值,才注册bean到IOC容器。
自定义starter
需求:
- 需求:自定义aliyun-oss-spring-boot-starter,完成阿里云0SS操作工具类Aliyun0SSUtils 的自动配置
- 目标:引入起步依赖引入之后,要想使用阿里云开源软件,注入阿里云开源软件直接使用即可。
以往操作
//依赖
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.15.1</version>
</dependency>
// 参考官方SDK改写工具类
@Component
public class AliOSSUtils {
@Autowired
private AliOSSProperties aliOSSProperties;
public String upload(MultipartFile file) throws IOException {
String endpoint = aliOSSProperties.getEndpoint();
String accessKeyId = aliOSSProperties.getAccessKeyId();
String accessKeySecret = aliOSSProperties.getAccessKeySecret();
String bucketName = aliOSSProperties.getBucketName();
//获取上传文件输入流
InputStream inputStream = file.getInputStream();
//避免文件覆盖
String originalFilename = file.getOriginalFilename();
String fileName = UUID.randomUUID().toString()+originalFilename.substring(originalFilename.lastIndexOf("."));
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId,accessKeySecret);
ossClient.putObject(bucketName,fileName,inputStream);
String url = endpoint.split("//")[0]+"//"+bucketName+"."+endpoint.split("//")[1]+"/"+fileName;
ossClient.shutdown();
return url;
}
}
//yml 配置
#自定义
aliyun:
oss:
endpoint: https://oss-cn-hangzhou.aliyuncs.com
accessKeyId: xxx
accessKeySecret: xxx
bucketName: xxx
//实体类加载yml配置参数
@Data
@Component
@ConfigurationProperties(prefix = "aliyun.oss")
public class AliOSSProperties {
private String endpoint;
private String accessKeyId;
private String accessKeySecret;
private String bucketName;
}
//@component 交给ioc容器
现在实现步骤
- 创建aliyun-oss-spring-boot-starter 模块
- 创建aliyun-oss-spring-boot-autoconfigure模块,在starter中引入该模块
- 在aliyun-oss-spring-boot-autoconfigure 模块中的定义自动配置功能,并定义自动配置文件 META-INF/spring/xxxx.imports
- 创建aliyun-oss-spring-boot-starter 模块 只留下pom 引入aliyun-oss-sping-boot-autoconfigure
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-oss-sping-boot-autoconfigure</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
- aliyun-oss-spring-boot-autoconfigure模块
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.15.1</version>
</dependency>
AliOSSUtils
public class AliOSSUtils {
private AliOSSProperties aliOSSProperties;
public AliOSSProperties getAliOSSProperties() {
return aliOSSProperties;
}
public void setAliOSSProperties(AliOSSProperties aliOSSProperties) {
this.aliOSSProperties = aliOSSProperties;
}
public String upload(MultipartFile file) throws IOException {
String endpoint = aliOSSProperties.getEndpoint();
String accessKeyId = aliOSSProperties.getAccessKeyId();
String accessKeySecret = aliOSSProperties.getAccessKeySecret();
String bucketName = aliOSSProperties.getBucketName();
//获取上传文件输入流
InputStream inputStream = file.getInputStream();
//避免文件覆盖
String originalFilename = file.getOriginalFilename();
String fileName = UUID.randomUUID().toString()+originalFilename.substring(originalFilename.lastIndexOf("."));
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId,accessKeySecret);
ossClient.putObject(bucketName,fileName,inputStream);
String url = endpoint.split("//")[0]+"//"+bucketName+"."+endpoint.split("//")[1]+"/"+fileName;
ossClient.shutdown();
return url;
}
}
AliOSSProperties
@Data
@ConfigurationProperties(prefix = "aliyun.oss")
public class AliOSSProperties {
private String endpoint;
private String accessKeyId;
private String accessKeySecret;
private String bucketName;
}
- 模块中的定义自动配置功能
@Configuration
@EnableConfigurationProperties(AliOSSProperties.class)
public class AliOSSAutoConfiguration {
@Bean
public AliOSSUtils aliOSSUtils(AliOSSProperties aliOSSProperties){
AliOSSUtils aliOSSUtils = new AliOSSUtils();
aliOSSUtils.setAliOSSProperties(aliOSSProperties);
return aliOSSUtils;
}
}
- 并定义自动配置文件 META-INF/spring/xxxx.imports
resources文件下新建
META-INF\spring\org.springframework.boot.autoconfigure.AutoConfiguration.imports
内容
com.aliyun.oss.AliOSSAutoConfiguration
- 测试
新建module–pom引入自定义starter aliyun-oss-sping-boot-starter
@RestController
public class UploadController {
@Autowired
private AliOSSUtils aliOSSUtils;
@PostMapping("/upload")
public String upload(MultipartFile image) throws Exception{
return aliOSSUtils.upload(image);
}
}
错误提示
idea可能会出现上述提示,不用管直接运行测试。知道怎么解决的铁子们可以留言
文章来源:https://blog.csdn.net/qq_44761778/article/details/134995294
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!