来处:是spring项目中的一个子项目css
优势 (被称为搭建项目的脚手架)html
减小一切xml配置,作到开箱即用,快速上手,专一于业务而非配置前端
从建立项目上: -- 快速建立独立运行的spring项目以及与主流框架集成(云计算)java
从运行项目上:--使用嵌入式的Servlet 容器,应用无需打成war包 直接打成jar包使用java -jar就能够启动mysql
从项目jar包上 :-- starters 自动依赖与版本控制,大量的自动配置。jquery
微服务:linux
一个应用就是一组小型的服务,能够经过http的方式进行互通git
每个功能元素最终都是一个可独立替换和独立升级的软件单元web
查看maven版本 mvn -vredis
搭建一个springboot应用(由浅到深的了解便于记忆)
1. 1.1同以往搭建项目同样首先重视的就是环境配置
jar包会被场景启动器所替换首先会引入场景启动器
<!--全部的springboot应用都须要以该工程为父工程包含了启动springboot所需的所有jar包--> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.6.RELEASE</version> </parent>
从官网上拷贝下来的依赖须要什么场景启动器就引入什么场景启动器就行
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>com.jayway.jsonpath</groupId> <artifactId>json-path</artifactId> <scope>test</scope> </dependency>
也能够加入日志文件
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </dependency>
</dependencies> <properties> <java.version>1.8</java.version> </properties>
spring的几个项目结构介绍
libraries 库(maven自定下载的jar包)
compiler.xml 编译器(主要用于maven初始化的编译)
modules.xml(模块的xml)
.mvn :主要用于版本切换 由于maven的版本和插件配合并非那么完美,.mvn为解决这个问题有一个第三方的插件wrapper可使用
properties文件中记录你要使用的maven版本当用户执行mvn的clear命令时发现当前用户使用的maven版本和用户指望的版本不同那么就下载指望的maven版本。
.gitignore 的做用 忽略不须要上传的文件
demo.iml idea工程的配置文件是当前project的一些配置信息
开启第一个springboot项目
MVC 中 建立的第一个Controller类
注解
@RestController /*ResponseBody+Controller 返回json类型的数据*/ http://www.javashuo.com/article/p-finclvbr-bh.html RESTFUL风格基础概念
@RequestMapping("hello") 请求映射 能够配置全局的也能够配置局部的
@EnableAutoConfiguration /*启用自动配置若是不声明那么他就认为你不须要自动配置*/
实际上springboot的自动配置是根据你引入了什么依赖,若是你引入了他就会给你自动配置这些须要的config 或则javabean 或者class
后来我将springboot启动类换到了另一个方法中
出现了一个异常 http://www.javashuo.com/article/p-fwzwursd-t.html 解决办法
由于我换了类可是忘记了换类名因此才报错
** WARNING ** : Your ApplicationContext is unlikely to start due to a @ComponentScan of the default package.
这个是由于 ComponentScan注解的默认扫描范围是启动程序XxxApplication. java所在目录及其下的全部子包。
因此你不能够直接放在java目录下须要建一个父包 而后进行扫描,这时就能够了
对比之前的写法
Properties properties = new Properties(); properties.load(JDBCUtil.class.getResourceAsStream("/jdbc.properties"));
底层使用流来进行读取
springboot 如今的写法
1.在resources下建立jdbc.properties
@Configuration //声明一个类是java配置类至关于一个xml配置文件
@PropertySource("classpath:jdbc.properties") //指定外部属性文件 读取咱们的资源文件
public class jdbcConfiguration {
//声明jdbc的配置文件
//使用属性注入的方式
@Value("${jdbc.driverClassName}")
private String driverClassName;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean //相似一个bean标签将方法的返回值加入bean容器
public DataSource dateSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(this.driverClassName);
dataSource.setUrl(this.url);
dataSource.setUsername(this.username);
dataSource.setPassword(this.password); 这里用上this主要是为了区分红员变量和局部变量
return null;
}
}
升级写法
设置set/get方法
springboot 给咱们提供了四种注入方式 第一种是set/get方式也就是上面那种方式
第二种是经过 构造方法
第三种:经过bean方法的形参也能够自动注入
第四种:是一种更加简单的方法
@ConfigurationProperties(prefix = "jdbc") 不只能够用在类上也能够用在方法上。
底层使用Datasource 的构造方法 get/set方法
4.yml文件中的值不能以*开头,能够用 "*" 加个引号开头。
/*来标注主程序类,来讲明这是一个spring boot应用 * */ @SpringBootApplication public class SpringBoot01ConfigApplication { public static void main(String[] args) { /*springboot应用启动起来*/ SpringApplication.run(SpringBoot01ConfigApplication.class, args); }
package cn.edu.aynu.springboot01config; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class MyController { @RequestMapping("/some") public String doFirst(){ return "Helloworld"; } }
将一下工程的监控器,监控工程的运行状态
Actuator是Spring Boot提供的一个可插拔模块,用于对工程进行监控。其经过不一样的监控终端实现不一样的监控功能。其功能与Dubbo的监控中心相似,不一样的是,Dubbo的监控中心是须要专门部署的,而Spring Boot的Actuator是存在于每个工程中的。官网https://docs.spring.io/spring-boot/docs/2.0.5.RELEASE/reference/htmlsingle/#production-ready
导入依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
有一点要注意:Actuator 与 elasticsearch 是相互冲突的。若是导入了 Acturtor 就不要再使用 elasticserach 不然报错
server: port: 8081 tomcat: uri-encoding: UTF-8 management: server: port: 9999 servlet: context-path: /xxx endpoints: web: base-path: /base endpoint: health: show-details: always
{ "status": "DOWN", "details": { "diskSpace": { "status": "UP", "details": { "total": 15453913088, "free": 7720787968, "threshold": 10485760 } }, "redis": { "status": "DOWN", "details": { "error": "org.springframework.data.redis.RedisConnectionFailureException: Unable to connect to Redis; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to localhost:6379" } } } }
management.server.port=9999 management.server.servlet.context-path=/xxx management.endpoints.web.base-path=/actuator #自定义info 信息 info.company.name=abc info.auth.name=lisi
{ "company": { "name": "abc" }, "auth": { "name": "lisi" } }
开放全部的监控终端
management.endpoints.web.exposure.include=*
排除某些不想开放的终端
management.endpoints.web.exposure.exclude=env,beans
经常使用的监控终端
在配置文件中取出属性值
方法一:
使用主配置文件或者自定义的配置文件均可以 @RestController @PropertySource(value = "classpath:student.properties",encoding = "utf-8") /*@PropertySource(value = "application.properties")*/ public class controller { @Value("${student.id}") int id; @Value("${student.name}") String name; @Value("${student.age}") int age; @RequestMapping("/hello") public String handler(){ return id+","+name+","+age; }
student.id = 111111111 student.name = zhu student.age = 12
可是建议通常不要写在主主配置文件中
方法二
将实体类声明为一个组件,并使用ConfigurationProperties注解将配置文件中的属性赋值上去
package cn.edu.aynu.bean; import com.sun.tracing.dtrace.ArgsAttributes; import lombok.Data; import lombok.NoArgsConstructor; import lombok.ToString; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; @Component @ConfigurationProperties(prefix = "student") public class Student { private int id; private String name; private int age; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Student{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}'; } }
student: id: 12 name: lisi age: 34
package cn.edu.aynu.controller; import cn.edu.aynu.bean.Student; import cn.edu.aynu.service.ServiceHandler; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.PropertySource; import org.springframework.web.bind.annotation.*; @RestController public class controller { @Autowired Student student; @RequestMapping("/hello") public String handler(){ System.out.println(student); return "/hello"; } }
controller 中须要注意一点,当咱们使用自动注入bean的时候,是能够获得值的,可是若是咱们在从新定义一个剧不能获得值了,应为那就至关因而重写了这个方法。
须要注意一点,有时候咱们不只仅须要的属性只是int 或者是String 咱们可能须要的是map 或者list
若是配置文件没有了提示就导入这个jar包
<!‐‐导入配置文件处理器,配置文件进行绑定就会有提示‐‐>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐configuration‐processor</artifactId>
<optional>true</optional>
</dependency>
能够将程序打包成jar包
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
怎么打成jar包
能够直接在命令行上进行启动执行
执行成功 这个路径是Controller里面的requestMapping
探究原理
自动导入的jar包
父项目
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.0.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent>
因此又叫他Springboot的仲裁中心
导入的依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
主程序类
package cn.edu.aynu.springboot01config; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /*来标注主程序类,来讲明这是一个spring boot应用 * */ @SpringBootApplication public class SpringBoot01ConfigApplication { public static void main(String[] args) { /*springboot应用启动起来*/ SpringApplication.run(SpringBoot01ConfigApplication.class, args); } }
/*这个类的全部方法返回的数据写给浏览器,若是是对象转为json格式*/ /*@ResponseBody @Controller*/ @RestController /*@RestController 直接表明了@RequestBody 和@Controller*/ public class MyController { @RequestMapping("/some") public String doFirst(){ return "Helloworld"; } }
application.properties的配置文件
server.port=9090 # 服务端口号 server.tomcat.uri-encoding=UTF-8 #以Tomcat为web容器时的字符编码 spring.application.name=customer # 应用名称,通常就是项目名称,这个名称在SpringCloud中比较关键 spring.profiles.active=dev #指定当前的活动配置文件,主要用于多环境多配置文件的应用中 spring.http.encoding.charset=UTF-8 #http请求的字符编码 spring.http.multipart.max-file-size=10MB #设置文件上传时单个文件的大小限制 spring.http.multipart.max-request-size=100MB #设置文件上传时总文件大小限制 spring.thymeleaf.prefix=classpath:/templates/ #配置在使用Thymeleaf作页面模板时的前缀,即页面所在路径 spring.thymeleaf.suffix=.html #设置在使用Thymeleaf作页面模板时的后缀 spring.thymeleaf.cache=false #设置在使用Thymeleaf作页面模板时是否启用缓存 spring.mvc.static-path-pattern=/** #设置静态资源的请求路径 spring.resources.static-locations=classpath:/static/,classpath:/public/ #指定静态资源的路径 ##如下是使用MySQL数据库的配置 hibernate.dialect=org.hibernate.dialect.MySQL5Dialect #指定数据库方言 hibernate.show_sql=true #是否显示sql语句 hibernate.hbm2dll.auto=update #设置使用Hibernate的自动建表方式 entitymanager.packagesToScan=com.zslin #设置自动扫描的包前缀 spring.datasource.url=jdbc:mysql://localhost:3306/customer?\ useUnicode=true&characterEncoding=utf-8&useSSL=true&autoReconnect=true #数据库连接 spring.datasource.username=root #数据库用户名 spring.datasource.password=123 #数据库用户对应的密码 spring.datasource.driver-class-name=com.mysql.jdbc.Driver #数据库驱动名称
@ConfigurationProperties主要做用:就是绑定application.properties中的属性
使用方法
@ConfigurationProperties(prefix = "spring.datasource")
application.properties 文件 spring.datasource.password=root spring.datasource.username=root spring.datasource.url=jdbc:mysql:///jdbc spring.datasource.driver-class-name=com.alibaba.druid.proxy.DruidDriver
springboot的包扫描问题
根据英文的提示是在配置中找不到一个指定自动注入类型的bean,SpringBoot项目的Bean装配默认规则是根据Application类所在的包位置从上往下扫描!Application类是指SpringBoot项目入口类。
这个类的位置很关键:若是mapper、service所在包不在其子包下,则不会被扫描。
即, 把Application类放到mapper、service所在包的上级,
两种解决办法:
1 .将接口与对应的实现类放在与application启动类的同一个目录或者他的子目录下,这样注解能够被扫描到,这是最省事的办法
2 .在指定的application类上加上这么一行注解,手动指定application类要扫描哪些包下的注解(图3)
图3
@ComponentScan(basePackages = "cn.edu.aynu.*")
server: port: 8087
xml
<server> port:8087 </server>
<!--导入配置文件处理器,配置文件进行绑定就会有提示-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
作一个小练习
定义两个类 在yaml文件中给属性赋值
people: lastName: zs age: 12 boss: ls birth: 2017/12/14 maps: {k1: v1,k2: v2} lists: - lisi - zhou dog: name: 小狗 age: 23
如今如何将两个属性与java bean类进行绑定
/*将配置文件中的每个值映射到这个组件中 * @ConfigurationProperties 告诉springboot这个类中的属性和配置文件的属性进行绑定 * 加上前缀是由于配置文件中能够写入不少的属性值要找到相对应的那一个。进行一一映射 * 只有这个组件是容器中的组件才能使用容器中提供的功能,因此要将这个类声明为组件 * */ @Component @ConfigurationProperties(prefix = "people") public class People { private String lastName; private Integer age; private Boolean boss; private Date birth; private Map<String,Object> maps; private List<Object> lists; private Dog dog;
public class Dog { private String name; private Integer age;
@RunWith(SpringRunner.class) @SpringBootTest public class SpringBoot01ConfigApplicationTests { @Autowired People people; @Test public void contextLoads() { System.out.println(people); }
执行成功
在properties配置文件中进行配置
people.last-name=zs people.age=23 people.birth=2013/12/12 people.boss=false people.maps.k1=v1 people.maps.k2=v2 people.lists=a,b,c people.dog.name=li people.dog.age=34
若是在peoperties文件中产生了乱码就在idea中改变一下,file-setting-输入file Enconding 调一下
@Component //@ConfigurationProperties(prefix = "people") public class People { /*在spring中进行给变量赋值 * <bean> * <property name="" values="字面量/#{}从EL表达式中获取/${}从配置文件,环境变量中获取"></property> * </bean>那么注解也支持这几种方式 * 采用注解的方式 */ @Value("${people.last-name}") private String lastName; @Value("#{11*2}") private Integer age; private Boolean boss; private Date birth; private Map<String,Object> maps; private List<Object> lists; private Dog dog;
@ConfigurationProperties(prefix = "people")表明从全局配置文件中获取值,本身也能够定义配置文件
@PropertySource(value = {"classpath:people.properties"}) @Component @ConfigurationProperties(prefix = "people") public class People { /*在spring中进行给变量赋值 * <bean> * <property name="" values="字面量/#{}从EL表达式中获取/${}从配置文件,环境变量中获取"></property> * </bean>那么注解也支持这几种方式 * 采用注解的方式 */ @Value("${people.last-name}") private String lastName; @Value("#{11*2}") private Integer age; private Boolean boss; private Date birth; private Map<String,Object> maps; private List<Object> lists; private Dog dog;
这里面须要补充一点,也是须要注意的地方
@PropertySources 和 ConfigurationProprtties 这两个注解式相辅相成的
若是只是加上 @COnfigurationSources这个注解那么,与bean绑定的属性值默认是从主配置文件中加载,
可是若是加上 PropertySources这个注解,则能够从本身自定义的 XXX.properties 中加载。
@PropertySource(value = {"classpath:person.properties"}) //加载指定的配置文件;
@ImportResource //导入Spring的配置文件,让配置文件里面的内容生效;Spring Boot里面没有Spring的配置文件,咱们本身编写的配置文件,也不能自动识别;想让Spring的配置文件生效,加载进来;@ImportResource标注在一个配置类上
用法:
@ImportResource(locations = {"classpath:beans.xml"})
导入Spring的配置文件让其生效这个配置文件主要是让配置文件进行生效。
<?xml version="1.0" encoding="UTF‐8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema‐instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring‐beans.xsd"> <bean id="helloService" class="com.atguigu.springboot.service.HelloService"></bean> </beans>
@Bean
SpringBoot推荐给容器中添加组件的方式;推荐使用全注解的方式一、配置类@Configuration------>Spring配置文件二、使用@Bean给容器中添加
举个例子
* 在配置文件中用<bean><bean/>标签添加组件 * */ @Configuration public class MyAppConfig { //将方法的返回值添加到容器中;容器中这个组件默认的id就是方法名 @Bean public HelloService helloService02(){ System.out.println("配置类@Bean给容器中添加组件了..."); return new HelloService(); } }
@ConfigurationProperties:告诉SpringBoot将本类中的全部属性和配置文件中相关的配置进行绑定;prefix = "person":配置文件中哪一个下面的全部属性进行一一映射只有这个组件是容器中的组件,才能容器提供的@ConfigurationProperties功能;@ConfigurationProperties(prefix = "person")默认从全局配置文件中获取值;
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="hello" class="cn.edu.aynu.springboot01config.helloService"></bean> </beans>
@Test public void testService(){ boolean helloService = ioc.containsBean("hello"); System.out.println(helloService); }
@ImportResource(locations = {"classpath:beans.xml"}) @SpringBootApplication public class SpringBoot01ConfigApplication { public static void main(String[] args) { /*springboot应用启动起来*/ SpringApplication.run(SpringBoot01ConfigApplication.class, args); } }
/*@Configuration 指明当前类就是一个配置类,用来代替以前的spring配置文件 * 在标签中使用<bean></bean>添加组件 * * */ @Configuration public class RegisterConfig { /*将方法的返回值添加到容器中;容器中这个组件默认的id就是方法名*/ @Bean public helloService helloService02(){ return new helloService(); } }
package cn.edu.aynu.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * Description: review-project * Created by lenovo on 2019/4/26 16:33 */ @Configuration //告诉springboot 这是一个配置类 public class MyConfig { @Bean //将方法的返回值添加到容器中,容器中这个组件默认的id就是方法名 public HelloService configApp(){ System.out.println("@bean给容器中添加了组件,根据方法名这到这个类"); return new HelloService(); } }
2019-04-26 16:38:36.327 INFO 11556 --- [ main] cn.edu.aynu.ReviewApplication : Starting ReviewApplication on LAPTOP-4U4DHM78 with PID 11556 (E:\sturts2\review-project\target\classes started by lenovo in E:\sturts2\review-project) 2019-04-26 16:38:36.336 INFO 11556 --- [ main] cn.edu.aynu.ReviewApplication : No active profile set, falling back to default profiles: default 2019-04-26 16:38:38.298 INFO 11556 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode! 2019-04-26 16:38:38.302 INFO 11556 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data repositories in DEFAULT mode. 2019-04-26 16:38:38.414 INFO 11556 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 88ms. Found 0 repository interfaces. 2019-04-26 16:38:39.418 INFO 11556 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8081 (http) 2019-04-26 16:38:39.449 INFO 11556 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2019-04-26 16:38:39.449 INFO 11556 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.17] 2019-04-26 16:38:39.653 INFO 11556 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2019-04-26 16:38:39.653 INFO 11556 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 3207 ms @bean给容器中添加了组件,根据方法名这到这个类
经过这个控制台打印的信息能够看出 Root WebApplicationContext: initialization completed in 3207 ms
当WebApplicationContext 初始化完成后,就打印了自定义信息
看一下控制台的输出就能够知道程序执行的前后顺序,挑几个我认识的
1.先检查一个有没有多环境选择的profile
No active profile set, falling back to default profiles: default
2.是对 Spring Data repository 的扫描
Finished Spring Data repository scanning in 88ms. Found 0 repository interfaces.
Tomcat initialized with port(s): 8081 (http)
Starting service [Tomcat]
Starting Servlet engine: [Apache Tomcat/9.0.17]
Initializing Spring embedded WebApplicationContext
Root WebApplicationContext: initialization completed in 3207 ms
.................
在配置文件中的代码,通常都是按照配置文件的前后循序执行。
解释一下spring Data (https://www.cnblogs.com/airycode/p/6535323.html能够参考这个博主)
Repository 接口是 Spring Data 的一个核心接口,它不提供任何方法,开发者须要在本身定义的接口中声明须要的方法 public interface Repository<T, ID extends Serializable> { } Spring Data可让咱们只定义接口,只要遵循 Spring Data的规范,就无需写实现类。 与继承 Repository 等价的一种方式,就是在持久层接口上使用 @RepositoryDefinition 注解,并为其指定 domainClass 和 idClass 属性。以下两种方式是彻底等价的 Repository 的子接口 基础的 Repository 提供了最基本的数据访问功能,其几个子接口则扩展了一些功能。它们的继承关系以下: 1.Repository: 仅仅是一个标识,代表任何继承它的均为仓库接口类 2.CrudRepository: 继承 Repository,实现了一组 CRUD 相关的方法 3.PagingAndSortingRepository: 继承 CrudRepository,实现了一组分页排序相关的方法 4.JpaRepository: 继承 PagingAndSortingRepository,实现一组 JPA 规范相关的方法 5.自定义的 XxxxRepository 须要继承 JpaRepository,这样的 XxxxRepository 接口就具有了通用的数据访问控制层的能力。 6.JpaSpecificationExecutor: 不属于Repository体系,实现一组 JPA Criteria 查询相关的方法 https://www.cnblogs.com/airycode/p/6535323.html
---表明一个文档
配置文件的加载顺序:
springboot启动会扫描如下位置的application.properties或者application.yml做为springboot的默认配置文件
-file:./config
-file:./
-classpath:/config/
-classpath:/
优先级从高到低,高优先级的配置会覆盖低优先级的配置。
最重要的是,springboot会从这四个位置所有加载配置文件,想成互补配置
咱们还能够经过改变
spring.config.location 来改变默认配置文件的位置,可是这个方式有一个前提就是须要在项目打包好之后,启动项目的时候指定配置文件的新位置,
全部的配置文件都会造成互补配置
java -jar spring-boot-02-config-02-0.0.1-SNAPSHOT.jar --spring.config.location=G:/application.properties
刚才讲的都是内部文件的加载顺序,如今讲一下外部文件的加载顺序
1.命令行参数,全部你命令均可以在命令行中进行指定
java -jar spring-boot-02-config-02-0.0.1-SNAPSHOT.jar --server.port=8087 --server.context-path=/abc
特色:能够同时加载多个配置项,可是多个配置项之间须要使用空格隔开
2由jar包外向jar包内进行寻找
优先加载带profile的
jar包外部的application-{profile}.properties或application.yml(带spring.profile)配置文件
jar包内部的application-{profile}.properties或application.yml(带spring.profile)配置文件
再来加载不带profile的
jar包外部的application.properties或application.yml(不带spring.profile)配置文件
jar包内部的application.properties或application.yml(不带spring.profile)配置文件
配置文件上进行指定
@Configuration注解类上的@PropertySource
经过SpringApplication.setDefaultProperties指定的默认属性
8.自动配置原理
springboot启动的时候加载了主启动类开启了自动配置功能
@EnableAutoConfiguration的做用是:
@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 {
@EnableAutoConfiguration 里面封装了
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration {
利用EnableAutoConfigurationImportSelector,先判断是属于什么注解,而后再进行下一步操做
类的全名就做为组件的id.
List configurations = getCandidateConfigurations(annotationMetadata, attributes);获取候选的配置,也就是将候选的组件组件获取内容保存起来。
接着,有一个类SpringFactoriesLoader.loadFactoryNames()
扫描全部jar包类路径下 META‐INF/spring.factories把扫描到的这些文件的内容包装成properties对象从properties中获取到EnableAutoConfiguration.class类(类名)对应的值,而后把他们添加在容器中
将 类路径下 META-INF/spring.factories 里面配置的全部EnableAutoConfiguration的值加入到了容器中;
这时,自定义配置才算真正的加载到容器中
一但这个配置类生效;这个配置类就会给容器中添加各类组件;这些组件的属性是从对应的properties类中获取
的,这些类里面的每个属性又是和配置文件绑定的;
全部在配置文件中能配置的属性都是在xxxxProperties类中封装者‘;配置文件能配置什么就能够参照某个功
能对应的这个属性类精髓:
1)、SpringBoot启动会加载大量的自动配置类
2)、咱们看咱们须要的功能有没有SpringBoot默认写好的自动配置类;
3)、咱们再来看这个自动配置类中到底配置了哪些组件;(只要咱们要用的组件有,咱们就不须要再来配置了)
4)、给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。咱们就能够在配置文件中指定这
些属性的值;
xxxxAutoConfigurartion:自动配置类;
给容器中添加组件
xxxxProperties:封装配置文件中相关属性
细节
一、@Conditional派生注解(Spring注解版原生的@Conditional做用)
做用:必须是@Conditional指定的条件成立,才给容器中添加组件,配置配里面的全部内容才生效;
自动配置类在必定条件下才能生效 咱们怎么知道哪些配置类生效
咱们能够经过启用 debug=true属性;来让控制台打印自动配置报告,这样咱们就能够很方便的知道哪些自动配置
类生效;
docker pull mysql
SpringBoot与数据访问
JDBC
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring‐boot‐starter‐jdbc</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql‐connector‐java</artifactId> <scope>runtime</scope> </dependency>
spring: datasource: username: root password: 123456 url: jdbc:mysql://192.168.15.22:3306/jdbc driver‐class‐name: com.mysql.jdbc.Driver
效果:
默认是用org.apache.tomcat.jdbc.pool.DataSource做为数据源;
数据源的相关配置都在DataSourceProperties里面;
public interface DataSource extends CommonDataSource, Wrapper { Connection getConnection() throws SQLException; Connection getConnection(String username, String password) throws SQLException;
abstract class DataSourceConfiguration { @SuppressWarnings("unchecked") protected static <T> T createDataSource(DataSourceProperties properties, Class<? extends DataSource> type) { return (T) properties.initializeDataSourceBuilder().type(type).build(); } /** * Tomcat Pool DataSource configuration. */ @Configuration @ConditionalOnClass(org.apache.tomcat.jdbc.pool.DataSource.class) @ConditionalOnMissingBean(DataSource.class) @ConditionalOnProperty(name = "spring.datasource.type", havingValue = "org.apache.tomcat.jdbc.pool.DataSource", matchIfMissing = true) static class Tomcat { @Bean @ConfigurationProperties(prefix = "spring.datasource.tomcat") public org.apache.tomcat.jdbc.pool.DataSource dataSource( DataSourceProperties properties) { org.apache.tomcat.jdbc.pool.DataSource dataSource = createDataSource( properties, org.apache.tomcat.jdbc.pool.DataSource.class); DatabaseDriver databaseDriver = DatabaseDriver .fromJdbcUrl(properties.determineUrl()); String validationQuery = databaseDriver.getValidationQuery(); if (validationQuery != null) { dataSource.setTestOnBorrow(true); dataSource.setValidationQuery(validationQuery); } return dataSource; } } /** * Hikari DataSource configuration. */ @Configuration @ConditionalOnClass(HikariDataSource.class) @ConditionalOnMissingBean(DataSource.class) @ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.zaxxer.hikari.HikariDataSource", matchIfMissing = true) static class Hikari { @Bean @ConfigurationProperties(prefix = "spring.datasource.hikari") public HikariDataSource dataSource(DataSourceProperties properties) { HikariDataSource dataSource = createDataSource(properties, HikariDataSource.class); if (StringUtils.hasText(properties.getName())) { dataSource.setPoolName(properties.getName()); } return dataSource; } } /** * DBCP DataSource configuration. */ @Configuration @ConditionalOnClass(org.apache.commons.dbcp2.BasicDataSource.class) @ConditionalOnMissingBean(DataSource.class) @ConditionalOnProperty(name = "spring.datasource.type", havingValue = "org.apache.commons.dbcp2.BasicDataSource", matchIfMissing = true) static class Dbcp2 { @Bean @ConfigurationProperties(prefix = "spring.datasource.dbcp2") public org.apache.commons.dbcp2.BasicDataSource dataSource( DataSourceProperties properties) { return createDataSource(properties, org.apache.commons.dbcp2.BasicDataSource.class); } } /** * Generic DataSource configuration. */ @Configuration @ConditionalOnMissingBean(DataSource.class) @ConditionalOnProperty(name = "spring.datasource.type") static class Generic { @Bean public DataSource dataSource(DataSourceProperties properties) { return properties.initializeDataSourceBuilder().build(); } }
自动配置原理:
org.springframework.boot.autoconfigure.jdbc:
一、参考DataSourceConfiguration,根据配置建立数据源,默认使用Tomcat链接池;可使用
spring.datasource.type指定自定义的数据源类型;
二、SpringBoot默承认以支持;
org.apache.tomcat.jdbc.pool.DataSource、HikariDataSource、BasicDataSource、
自定义数据源类型
/** * Generic DataSource configuration. */ @ConditionalOnMissingBean(DataSource.class) @ConditionalOnProperty(name = "spring.datasource.type") static class Generic { @Bean public DataSource dataSource(DataSourceProperties properties) { //使用DataSourceBuilder建立数据源,利用反射建立响应type的数据源,而且绑定相关属性 return properties.initializeDataSourceBuilder().build(); } }
DataSourceInitializer:ApplicationListener;
做用:
1)、runSchemaScripts();运行建表语句;
2)、runDataScripts();运行插入数据的sql语句;
默认只须要将文件命名为:
schema‐*.sql、data‐*.sql
默认规则:schema.sql,schema‐all.sql;
可使用
schema:
‐ classpath:department.sql
指定位置
五、操做数据库:自动配置了JdbcTemplate操做数据库
spring: datasource: username: root password: root url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC driver-class-name: com.mysql.cj.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource schema: - classpath:sql/department.sql - classpath:sql/employee.sql
根据上面的配置,能够知道扫描 resources下面的.sql文件,而后加载这个sql文件,在数据库中进行建立
如何整合Druid数据源
首先确定是一个配置文件,当配置好了druid数据源以后,根据.sql文件也会在数据中建立表,
导入druid数据源 @Configuration public class DruidConfig {
@ConfigurationProperties(prefix = "spring.datasource") @Bean public DataSource druid(){
return new DruidDataSource(); } //配置Druid的监控 //一、配置一个管理后台的Servlet @Bean public ServletRegistrationBean statViewServlet(){ ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(),"/druid/*"); Map<String,String> initParams = new HashMap<>(); initParams.put("loginUsername","admin"); initParams.put("loginPassword","123456"); initParams.put("allow","");//默认就是容许全部访问 initParams.put("deny","192.168.15.21"); bean.setInitParameters(initParams); return bean; } //二、配置一个web监控的filter,这个在配置类中均可以进行配置,只须要把他加载进容器中。 @Bean public FilterRegistrationBean webStatFilter(){ FilterRegistrationBean bean = new FilterRegistrationBean(); bean.setFilter(new WebStatFilter()); Map<String,String> initParams = new HashMap<>(); initParams.put("exclusions","*.js,*.css,/druid/*"); bean.setInitParameters(initParams); bean.setUrlPatterns(Arrays.asList("/*")); return bean; } }
整合Mybaties
<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis‐spring‐boot‐starter</artifactId> <version>1.3.1</version> </dependency>
注解版
//指定这是一个操做数据库的mapper @Mapperpublic interface DepartmentMapper { @Select("select * from department where id=#{id}") public Department getDeptById(Integer id); @Delete("delete from department where id=#{id}") public int deleteDeptById(Integer id); @Options(useGeneratedKeys = true,keyProperty = "id") @Insert("insert into department(departmentName) values(#{departmentName})") public int insertDept(Department department); @Update("update department set departmentName=#{departmentName} where id=#{id}") public int updateDept(Department department); }
问题:
自定义MyBatis的配置规则;给容器中添加一个ConfigurationCustomizer;
@org.springframework.context.annotation.Configuration public class MyBatisConfig { @Bean public ConfigurationCustomizer configurationCustomizer(){ return new ConfigurationCustomizer(){ @Override public void customize(Configuration configuration) {
//设置驼峰命名法 configuration.setMapUnderscoreToCamelCase(true); } }; } }
使用MapperScan批量扫描全部的Mapper接口; @MapperScan(value = "com.atguigu.springboot.mapper") @SpringBootApplication public class SpringBoot06DataMybatisApplication { public static void main(String[] args) { SpringApplication.run(SpringBoot06DataMybatisApplication.class, args); } }
下面一个就是配置文件版
像spring 写sql文件同样声明配置文件,还有映射文件、
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="cn.edu.aynu.springboot.zhaoyujing.mapper.EmployeeMapper"> <!-- public Employee getEmpById(Integer id); public void insertEmp(Employee employee);--> <select id="getEmpById" resultType="cn.edu.aynu.springboot.zhaoyujing.entities.Employee"> SELECT * FROM employee WHERE id=#{id} </select> <insert id="insertEmp"> INSERT INTO employee(lastName,email,gender,d_id) VALUES (#{lastName},#{email},#{gender},#{dId}) </insert> <select id="getAll" resultType="cn.edu.aynu.springboot.zhaoyujing.entities.Employee"> SELECT * FROM employee </select> <delete id="delete"> delete from employee WHERE id=#{id} </delete> </mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--驼峰命名法-->
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
</configuration>
整合srpingData JPA
1.写一个实体类
//使用JPA注解配置映射关系 @Entity //告诉JPA这是一个实体类(和数据表映射的类) @Table(name = "tbl_user") //@Table来指定和哪一个数据表对应;若是省略默认表名就是user; public class User { @Id //这是一个主键 @GeneratedValue(strategy = GenerationType.IDENTITY)//自增主键 private Integer id;
@Column(name = "last_name",length = 50) //这是和数据表对应的一个列 private String lastName;
@Column //省略默认列名就是属性名 private String email;
2)、编写一个Dao接口来操做实体类对应的数据表(Repository)
也就是你能够自定义sql语句而后直接就能够被使用了,可是定义的方法名要符合一些规则
具体信息在下面这个网址中(https://www.cnblogs.com/zhulina-917/p/10504377.html)
//继承JpaRepository来完成对数据库的操做 public interface UserRepository extends JpaRepository<User,Integer> { }
基本的配置JpaProperties
spring: jpa: hibernate: # 更新或者建立数据表结构 ddl‐auto: update # 控制台显示SQL show‐sql: true
讲解springboot的启动配置原理
几个重要的事件回调机制
配置在META-INF/spring.factories
ApplicationContextInitializer
SpringApplicationRunListener
只须要放在ioc容器中
ApplicationRunner
CommandLineRunner
启动流程
initialize(sources); private void initialize(Object[] sources) { //保存主配置类 if (sources != null && sources.length > 0) { this.sources.addAll(Arrays.asList(sources)); } //判断当前是否一个web应用 this.webEnvironment = deduceWebEnvironment(); //从类路径下找到META‐INF/spring.factories配置的全部ApplicationContextInitializer;而后保存来 setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); //从类路径下找到ETA‐INF/spring.factories配置的全部ApplicationListener setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); //从多个配置类中找到有main方法的主配置类 this.mainApplicationClass = deduceMainApplicationClass(); }
运行run方法
public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start();
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
configureHeadlessProperty();
//获取SpringApplicationRunListeners;从类路径下META‐INF/spring.factories
SpringApplicationRunListeners listeners = getRunListeners(args);
//回调全部的获取SpringApplicationRunListener.starting()方法
listeners.starting();
try {
//封装命令行参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//准备环境
ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);
//建立环境完成后回调SpringApplicationRunListener.environmentPrepared();表示环境准备完成
Banner printedBanner = printBanner(environment);
//建立ApplicationContext;决定建立web的ioc仍是普通的ioc
context = createApplicationContext();
analyzers = new FailureAnalyzers(context);
//准备上下文环境;将environment保存到ioc中;并且applyInitializers();
//applyInitializers():回调以前保存的全部的ApplicationContextInitializer的initialize方法
//回调全部的SpringApplicationRunListener的contextPrepared();
prepareContext(context, environment, listeners, applicationArguments,printedBanner);
//prepareContext运行完成之后回调全部的SpringApplicationRunListener的contextLoaded();
//s刷新容器;ioc容器初始化(若是是web应用还会建立嵌入式的Tomcat);Spring注解版
//扫描,建立,加载全部组件的地方;(配置类,组件,自动配置)
refreshContext(context);
/ /从ioc容器中获取全部的ApplicationRunner和CommandLineRunner进行回调
//ApplicationRunner先回调,CommandLineRunner再回调
afterRefresh(context, applicationArguments);
//全部的SpringApplicationRunListener回调finished方法
listeners.finished(context, null);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
/ /整个SpringBoot应用启动完成之后返回启动的ioc容器;
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex);
}
}
事件的监听机制
配置在META-INF/spring.factories
ApplicationContextInitializer
public class HelloApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override public void initialize(ConfigurableApplicationContext applicationContext) { System.out.println("ApplicationContextInitializer...initialize..."+applicationContext); } }
SpringApplicationRunListener
public class HelloSpringApplicationRunListener implements SpringApplicationRunListener { //必须有的构造器 public HelloSpringApplicationRunListener(SpringApplication application, String[] args){ } @Override public void starting() { System.out.println("SpringApplicationRunListener...starting..."); } @Override public void environmentPrepared(ConfigurableEnvironment environment) { Object o = environment.getSystemProperties().get("os.name"); System.out.println("SpringApplicationRunListener...environmentPrepared.."+o); } @Override public void contextPrepared(ConfigurableApplicationContext context) { System.out.println("SpringApplicationRunListener...contextPrepared..."); } @Override public void contextLoaded(ConfigurableApplicationContext context) { System.out.println("SpringApplicationRunListener...contextLoaded..."); } @Override public void finished(ConfigurableApplicationContext context, Throwable exception) { System.out.println("SpringApplicationRunListener...finished..."); } }
配置(META-INF/spring.factories)
org.springframework.context.ApplicationContextInitializer=\ com.atguigu.springboot.listener.HelloApplicationContextInitializer org.springframework.boot.SpringApplicationRunListener=\ com.atguigu.springboot.listener.HelloSpringApplicationRunListener