程序 = 数据结构 + 算法 (程序员)
程序 = 面向对象 + 框架 (码农)
我们要学会ctrl+左键查看源码才能学习,而不是单纯去用
不断学习新知识(SpringBoot)
jar包与war包?
jar包相当于是java代码的打包,而我们webapp运行时需要额外的东西,比如tomcat,如果打成jar包相当于把服务器内嵌了, 而war包更像是将java代码和相应额外的东西一起打包。
什么是spring?
@Component注解代表为spring的组件
Spring是为了解决企业级应用开发的复杂性而创建的,简化开发。 Spring就是作为容器去管理你的类,Spring管理的类在整个服务器启动期间在内存中只生成一份。 Spring的Ioc(控制反转和依赖注入) 控制反转:就是由容器控制程序之间的(依赖)关系,而非传统实现中,由程序代码直 接操控。 依赖注入:组件之间的依赖关系由容器在运行期决定 ,由容器动态的将某种依赖关系注 入到组件之中。通俗点说,例如A,B两个类都交由spring管理,A中有B的引用,那么在配置中可以事先配置好,服务器启动时初始化A的时候会自动将B注入到A中, 而不用再A中再次去用new来初始化B。spring还可以对事物进行管理。将hibernate的sessionFactory交由spring进行管理。她封装了所有对事务处理的功能, 包括异常时事务回滚,操作成功时数据提交等复杂业务功能。这都是由Spring容器来管理,大大减少了程序员的代码量,也对事务有了很好的管理控制。 1.sqlsession是mybatis用来将代码与数据库连接,包括执行sql语句,使用数据库执行相应操作,处理sql参数,结果集处理返回 2.service操作dao层,pojo对应数据库,通过配置文件嵌套来加载 3.配置上下文可以将配置文件关联在一起方便注入,也可以手动通过import resource引入 4.配置dao接口扫描包可以不用手写实现类 5.注解和配置文件都可以实现自动注入
spring如何简化开发?
1.基于POJO的轻量级和最小侵入性编程 2.通过IOC,依赖注入(DI)和面向接口实现松耦合 3.基于切面(AOP)和惯例进行声明式编程 4.通过切面和模板(比如jdbctemplate)减少样式代码
SpringBoot(约定大于配置)
简化javaweb开发
SpringBoot的配置文件 1.项目元数据信息:创建的时候输入的Project Metadata部分,也就是Maven项目的基本元素,包括:groupld,artifactld,version,name,description等 2.parent:继承spring-boot-starter-parent的依赖管理,控制版本与打包等内容,要用什么功能用启动器启动就行(启动器就是第一层的配置文件) 3.dependencies:项目具体依赖,这里包含了spring-boot-starter-web用于实现HTTP接口(该依赖中包含了Spring MVC),官网对它的描述是: 使用Spring MVC构建Web(包括RESTful)应用程序的入门者,使用tomcat作为默认嵌入式容器。;spring-boot-starter-test用于编写单元测试的依赖包。当然还有更多功能模块 4.build:构建配置部分。默认使用了spring-boot-maven-plugin,配合spring-boot-starter-parent就可以把Spring Boot应用打包成JAR来直接运行。
单体应用架构
将所有的应用服务封装到一个应用中,这样做方便开发和测试,需要扩展时也只用将war复制多份,然后放到多个服务器上进行负载均衡就行; 但是缺点也很明显,只要修改一个非常小的地方,就要停掉服务,重新打包,部署这个应用和war包,而且对于一个大型应用来说,把所有东西放在一个应用里面, 维护和合作都是问题。
微服务架构
打破之前all in one的结构方式,把每个功能元素独立出来。把独立出来的功能元素动态组合,需要的功能元素才用来组合,需要多一些时可以整合多个元素功能。 所以微服务架构是对功能元素进行复制,而没有对整个应用进行复制。 节省调用资源,每个功能元素的服务都是一个可替换的,可独立升级的软件代码。
SpringBoot的Application的注解
@SpringBootConfiguration(springboot的配置) @Configuration(spring的配置类) @Component(说明这是一个组件) @EnableAutoConfiguration(自动配置类) @AutoConfigurationPackage(自动配置包) @Import({Registrar.class})(自动配置包注册) @Import({AutoConfigurationImportSelector.class})(自动配置导入选择) 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; }
所以Application其实是将启动类下的所有资源导入,SpringBoot所有自动配置都是在启动的时候扫描并加载:spring-boot-autoconfigure的spring.factories有所有的自动配置类,但是不一定生效,要判断是否有对应的start(启动器)。
1.springboot在启动时,从类路径下/META-INF/spring.factories获取指定的值
2.将这些自动配置的类导入容器,自动配置就会生效
3.整合javaEE,解决方案和自动配置的东西都在spring-boot-autoconfigure这个包
4.它会把所有需要导入的组件,以类名的方式返回,这些组件就会被添加到容器
SpringApplication类
这个类主要做四件事
1.推断应用的类型是普通项目还是Web项目
2.查找并加载所有可用的初始化器,设置到initializers属性中
3.找出所有的应用程序监听器,设置到listeners属性中
4.推断并设置main方法的定义类,找到运行的主类
Yaml
@PropertySource(value = "classpath:xxx.properties")可加载指定的不被spring扫描的配置文件,@Validated可进行JSR303数据校验
语法:properties只能保存键值对,但是yaml能存对象(并且对象通过@ConfigurationProperties(prefix = "对应的配置对象的名字,如下面的person")可以在配置文件里装配,不同于之前的属性上面写@Value,对象上面写@Autowired),数组,并且有行外和行内写法,{}代表对象,[]代表数组
properties: name=ityz; student.name=ityz; student.age=18; yaml: name: ityz(普通键值对); student: {name: ityz,age: 18}或者 student: name: ityz age: ${random.int}(给随机值也行,这是spring的el表达式) happy: false birthday: 2002/07/29 maps: {k1: v1,k2: v2} list: - code - girl - music dog: name: ${person.hello: hello}(占位符,如果没给值则默认为hello)_旺财 age: 3 (对象); pets: [cat,dog,pig]或者 pets: - cat - dog (数组)`
配置文件识别优先级,工作中可以用多个配置文件来实现不同环境的测试
1.file:./config/ 2.file:./ 3.classpath:/config/ 4.classpath:/ //classpath这里指的是resources目录,file指项目目录
Yaml还可以实现多文档模式,如下,以---间隔,以spring.profiles命名,以spring.profiles.active选择,如果用properties则需要多个文件,比如application-dev.properties。
server: port: 8081 spring: profiles: active: dev --- server: port: 8082 spring: profiles: dev --- server: port: 8083 spring: profiles: test
配置文件到底能写什么?
配置文件的固有规律:
xxxAutoConfiguration自动配置类帮我们自动装配东西,如果我们没有手动设置那就是默认值,而其中对应的xxxProperties由配置文件绑定,我们可以根据相应的名称去自定义值。就像之前的Application里面的注解,其实自动装配就是层层绑定。
首先我们要联系spring自动装配jar包的核心文件spring.factories所有组件来看,这里以HttpEncodingAutoConfiguration.java为例子
//表示这是一个配置类 @Configuration(proxyBeanMethods = false) //自动配置绑定类的注解:HttpProperties可以点进去看绑定的配置 @EnableConfigurationProperties({HttpProperties}) //Spring底层注解:根据不同条件来判断当前配置是否生效 @ConditionalOnWebApplication( type = ConditionalOnWebApplication.Type.SERVLET ) //字符编码过滤器 @ConditionalOnClass({CharacterEncodingFilter.class}) //判断是否存在配置,不存在就走默认 @ConditionalOnProperty( prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true ) //2.7版本以后的 @AutoConfiguration @EnableConfigurationProperties({ServerProperties.class}) @ConditionalOnWebApplication( type = Type.SERVLET ) @ConditionalOnClass({CharacterEncodingFilter.class}) @ConditionalOnProperty( prefix = "server.servlet.encoding", value = {"enabled"}, matchIfMissing = true )
可以通过配置文件中debug: true判断来查看哪些自动配置类生效,哪些没有生效
Spring Boot 2.7 新特性
自动配置变更(重要)
自动配置注册有了一个比较大的调整,之前都是写在下面 文件中的:
META-INF/spring.factories
现在改名了:
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
转存失败重新上传取消
另外格式也变了,Spring Boot 2.7 中直接每一行是一个自动配置类:
转存失败重新上传取消
编写格式确实是比之前方便多了,但文件名确实也太长了,比较难记。。。
需要注意的是:
为了向后兼容,META-INF/spring.factories 虽然现在被标识废弃了,但现在仍然可以使用,后续可能被彻底删除,建议使用新的规范。
Spring Boot 基础就不介绍了,推荐下这个实战教程:
新注解(@AutoConfiguration)
新增了一个自动配置注解 @AutoConfiguration
,用来代替之前的 @Configuration
,用于标识新自动配置注册文件中的顶级自动配置类,由 @AutoConfiguration
注解嵌套、导入进来的其他配置类可以继续使用 @Configuration
注解。
另外,为方便起见,@AutoConfiguration
注解还支持 after
, afterNames
, before
和 beforeNames
属性进行自动配置排序,用于代替之前的 @AutoConfigureAfter
和 @AutoConfigureBefore
注解。
这个注解可以说更加细分了吧,自动配置专用注解,用专门的注解来干专门的事,这样也可以用来区分用 @Configuration
标识的普通配置类。
静态资源
public void addResourceHandlers(ResourceHandlerRegistry registry) { if (!this.resourceProperties.isAddMappings()) { logger.debug("Default resource handling disabled"); } else { this.addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");(可以读取webjars) this.addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> { registration.addResourceLocations(this.resourceProperties.getStaticLocations()); if (this.servletContext != null) { ServletContextResource resource = new ServletContextResource(this.servletContext, "/"); registration.addResourceLocations(new Resource[]{resource}); } }); } } private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"};(这些目录下的静态资源都能读取,也是按优先级读取的) @ConfigurationProperties( prefix = "spring.mvc" ) public class WebMvcProperties { private String staticPathPattern = "/**";(代表可以自己绑定属性修改读取路径)