1.Spring Boot 入门
(1).基本原理
官网:
使用mybatis+spring+springMvc 整合在maven中需要加入很多依赖,写配置文件,打成war包 配置环境 很麻烦 所以spring使用来简化spring
优点
https://martinfowler.com/articles/
查看jdk版本 在cmd 中输入 java -version
查看maven版本
<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> <!--加入自定义的log配置文件--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </dependency>
springboot的基础入门
libraries 库(maven自定下载的jar包)
compiler.xml 编译器(主要用于maven初始化的编译)
misc.xml(混乱的,多种多样的)
modules.xml(模块的xml)
thriftCompiler.xml(节约,节俭)
workspace.xml
下面介绍.mvn
springboot中的.mvn主要用于版本切换因为maven的版本和插件配合并不是那么完美,.mvn为解决这个问题有一个第三方的插件wrapper可以使用
properties文件中记录你要使用的maven版本当用户执行mvn的clear命令时发现当前用户使用的maven版本和用户期望的版本不一样那么就下载期望的maven版本。
.gitignore 的作用 用于和git官网
demo.iml idea工程的配置文件是当前project的一些配置信息
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推荐给容器中添加组件的方式;推荐使用全注解的方式1、配置类@Configuration------>Spring配置文件2、使用@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:封装配置文件中相关属性
细节
1、@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:
1、参考DataSourceConfiguration,根据配置创建数据源,默认使用Tomcat连接池;可以使用
spring.datasource.type指定自定义的数据源类型;
2、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
指定位置
5、操作数据库:自动配置了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的监控 //1、配置一个管理后台的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; } //2、配置一个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