Administrator
发布于 2026-05-17 / 2 阅读
0

springboot

# Springboot是什么? javaweb框架,简化开发,扩展性好 ## 核心特点 - Jar形式独立运行 - 内嵌servlet容器,tomcat集成springmvc,spring - 简化Maven配置 - 自动装配dean - 提供基于http,ssh,telnet对运行时项目的监控 - 不需要任何xml文件,借助注解,properties实现spring配置 # 微服务 - MVC - MVVM:model view viewmodel - model:服务器上的业务逻辑操作 - view:页面 - viewmodel:model,view核心枢纽流入vue.js - view-》viewmodel--》model - 微服务:将原来的userservice===》模块 - 原来是所有的功能放在一个项目 - 微服务是将功能分开,向外提供接口 # 创建工程 方式一:https://start.spring.io/ 根据需要选择,最后添spring web依赖, 方式二:idea spring initilizer,需要自己添加web包 \`\`\`xml org.springframework.boot spring-boot-starter-parent 2.2.3.RELEASE org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-maven-plugin \`\`\` \`\`\`properties # properties格式 # 配置文件 # 更改端口号 server.port=8081 debug: true \`\`\` \`\`\`yaml # Yml(:后有空格) server: port: 8081 student: # 在实体类中注入,属性值必须相同,也可用于配置文件的注入 name: Dean${random.int} # spel表达式 age: 120 birthday: 2019/11/02 maps: {k1: v1,k2: v2} student: {name: Dean,age: 120} pets: - cat - dog - pig pets:\[cat,dog,pig\] \`\`\` \`\`\`java @Component @ConfigurationProperties(prefix = "student") @Validated //数据校验 public class Student { @Email("邮箱格式错误") private String email; } \`\`\` !\[img\](https://upload-images.jianshu.io/upload_images/3145530-8ae74d19e6c65b4c?imageMogr2/auto-orient/strip\|imageView2/2/format/webp) # 自定义启动图标(banner) http://patorjk.com/software/taag resources下复制保存为banner.txt # 常用maven命令 - clean:清理 - package:打包jar或war # 示例 \`\`\`java @RequestMapping("/login")    @ResponseBody    public User login(User user){      return user;    }    //User字段:userName pwd    //那么在前台接收到的数据为:'{"userName":"xxx","pwd":"xxx"}'效果等同于如下代码: @RequestMapping("/login")    public void login(User user, HttpServletResponse response){ response.getWriter.write(JSONObject.fromObject(user).toString()); } \`\`\` # 自动配置 - pom.xml - 核心依赖在父工程中 - 启动器 - \`\`\`xml org.springframework.boot spring-boot-starter-web \`\`\` - 需要什么功能就导入对应启动器 - https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-starter - 主程序 \`\`\`java @SpringBootApplication //标注是springboot应用 public class HellowordApplication { public static void main(String\[\] args) { //启动 SpringApplication.run(HellowordApplication.class, args); } } \`\`\` - SpringBootApplication包含比较重要的几个 - EnableAutoConfiguration(exclude={xxxConfiguration.class,yyy.Configuartion})启动自动配置 - AutoConfigurationPackage:自动配置包 - Import(AutoConfigurationPackages.Registrar.class) 导入选择器 包注册 - Import(AutoConfigurationImportSelector.class) 自动配置导入选择 - SpringBootConfiguration:springboot配置类 - Configuration:spring配置类 - Component:这一是spring - ComponentScan 扫描启动类同级别的包 # 多文件配置 classpath: - java文件夹 - resources文件夹 配置文件位置: - resources下 优先级最低 - resources/config/下 优先级较低 - 根目录下 优先级次高 - 根目录/config/下 优先级最高 多配置文件: - 默认的还是原名 - 建立其他的application-dev.properties - 测试开发时,每次分别使用不同properties,在主properties中指定: spring.profiles.active=dev ,指定配置文件 - \`\`\`yaml # --- 可用作分割,不用多个文件 server: port: 8081 spring: profile: active: dev --- server: port: 8081 spring: profile: dev --- server: port: 8081 spring: profile: test \`\`\` application.yaml 与spring.factories 有很大联系 spring.factories:可能需要配置文件类 - 里边是各种配置文件xxxxContiguration,需要xxxproperties,而properties需要自动注入,配置信息通过上边的方式,yaml装入 - 每个类的注解 - Configuration:表名是一个配置类 - EnableConfigurationProperties:允许yaml注入属性 - ConditionOnWebapplication:根据条件确定是否要配置 # WEB开发 ## 静态问价访问 - 不自己配置时:引入的js文件等静态依赖,默认会在Resources/webjars/下边 - \`\`\`xml org.webjars jquery 3.5.1 \`\`\` !\[image-20200816135456182\](https://i.loli.net/2020/08/16/tYJ8boeL1rpRDO9.png) - 不自己配置时: - classpath:/resources 优先级最高 - classpath:/static 其次 - classpath:/public 最后 - classpath:/mate-inf/resources - 自己配置 spring.mvc.static-path-pattern=/Dean/\\\*\\\*,classpath:/xxxx # 首页与图标 - 默认在静态文件夹下找index.html - 当网站是Restful类型时,用restfulcontroller注解 - 若要返回html,用controller注解 - html要位于template文件夹下 - 方法返回对应文件名,不带后缀 - 需要导入模板引擎 thymeleaf,等等 图标:静态文件夹下/favicon.ico # 自定义配置类 读取配置时会看是否有用户自定义配置,有的话使用用户的, 对于有的配置可有多个,例如视图解析器,就结合使用 \`\`\`java // 扩展springmvc ,dispatcherservlet @Configuration public class MyWebConfig implements WebMvcConfigurer { // 请求跳转 dzf--》hello 但url不变 @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/dzf").setViewName("/hello"); } // 实现视图解析器接口的类,我们就可以把他看做视图解析器 @Bean // 交给Springboot自动装配 public ViewResolver myViewResolver(){ return new MyViewResolver(); } //自定义视图解析器 public static class MyViewResolver implements ViewResolver{ @Override public View resolveViewName(String viewName, Locale locale) throws Exception { return null; } } } \`\`\` # 拦截器 \`\`\`java public class LoginHandlerInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Object loginUser = request.getSession().getAttribute("key"); if(loginUser==null){ request.getRequestDispatcher("/index.html").forward(request,response); return false; } return true; } } // 自定义webconfig中添加 @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/\*\*") .excludePathPatterns("/index.html","/user/login/\*\*","/css/\*\*"); } \`\`\` # 404页面 在template下边建立error文件夹建立404.html,对应错误会找到对应的 # 数据源配置 \`\`\`xml org.springframework.boot spring-boot-starter-jdbc mysql mysql-connector-java runtime com.alibaba druid 1.1.21 \`\`\` \`\`\`yaml spring: datasource: username: root password: 123456 url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true\&characterEncoding=utf-8\&serverTimezone=UTC driver-class-name: com.mysql.cj.jdbc.Driver # driver-class-name: com.mysql.jdbc.Driver this is lower Driver type: com.alibaba.druid.pool.DruidDataSource # druid's owner config, springboot doesn't these # if you wang to use this ,you should write one config initialSize: 5 minIdle: 5 # and so on # driud's plugins config filters: stat,wall,log4j maxPoolPreparedStatementPerConnectionSize: 20 useGlobalDataSourceStat: true connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500 \`\`\` \`\`\`java @Autowired DataSource dataSource; @Test void contextLoads() throws SQLException { // class com.zaxxer.hikari.HikariDataSource 也是一个连接池,类似c3p0,几乎是最快,默认,通过yaml中type选择 System.out.println(dataSource.getClass()); Connection connection = dataSource.getConnection(); System.out.println(connection); connection.close(); } \`\`\` \`\`\`java @Configuration public class DruidConfig { @ConfigurationProperties(prefix = "spring.datasource") @Bean public DataSource druidDataSource(){ return new DruidDataSource(); } // 后台监控 // springboot 内置servlet容器,没有web.xml 替代方法: ServletRegistrationBean 注册进去即可 @Bean public ServletRegistrationBean a(){ ServletRegistrationBean bean = new ServletRegistrationBean\<\>(new StatViewServlet(),"/druid/\*"); // 后台登录,账号密码 HashMap initParameters = new HashMap\<\>(); initParameters.put("loginUsername","admin"); // 名字不能改 initParameters.put("loginPassword","admin"); initParameters.put("allow",""); bean.setInitParameters(initParameters); return bean; } //filter public FilterRegistrationBean webSataFilter(){ FilterRegistrationBean bean = new FilterRegistrationBean(); bean.setFilter(new WebStatFilter()); // 可以过滤那些请求 Map initParameters = new HashMap\<\>(); // 不过滤 initParameters.put("exclusions","\*.js,\*.css,/durid/\*"); return bean; } } \`\`\` # 数据库JDBC \`\`\`java //jdbc ,有dao @Autowired JdbcTemplate jdbcTemplate; @RequestMapping("/getAll") public List\> userList(){ List\> list = jdbcTemplate.queryForList("select \* from user"); return list; } \`\`\` ## 整合mybatis(xml方式) 导入依赖 \`\`\`xml org.mybatis.spring.boot mybatis-spring-boot-starter 2.1.1 \`\`\` 配置yaml \`\`\`yaml mybatis: type-aliases-package: top.dean0731.model mapper-locations: classpath:mybatis/mapper/\*xml \`\`\` mapper 文件 \`\`\`java @Mapper @Repository public interface EmployeeMapper { List queryEmployeeList(); Employee queryEmployerById(); int addEmployee(Employee employee); int updateEmployee(Employee employee); int deleteEmployee(int id); } \`\`\` \`\`\`java //mapper 代替dao,Resource下mybatis/mapper/下创建配置文件 select \* from Employee \`\`\` # 整合mybatis(注解方式) \`\`\`java @Mapper @Repository public interface UsersMapper { @Select("select \* from t_user where name = #{name}") User findUserByName(@Param("name")String name); @Insert("insert into t_user(name,password)values(#{name},#{password})") void addUser(@Param("name")String name,@Param("password")String password); } \`\`\` # SpringSecurity(安全) - 与shiro类似,只不过类,名字不同而已 - 功能:认证,授权 - 以前使用拦截器,代码量很大,现在使用框架 - 功能权限,访问权限,菜单权限 - AOP思想 \`\`\`xml org.springframework.boot spring-boot-starter-security \`\`\` \`\`\`java @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { //首页都可以访问,其他不行, // 授权的规则 http.authorizeRequests() .antMatchers("/").permitAll() .antMatchers("/level1/\*").hasRole("vip1") .antMatchers("/level2/\*").hasRole("vip2") .antMatchers("/level3/\*").hasRole("vip3"); // 开启记住我功能 //http.rememberMe(); http.rememberMe().rememberMeParameter("remeber"); // 没有权限跳转到登录页面, // 没有认证到/login,认证失败到/login?error ,是自带的login页面与逻辑是一个请求 //http.formLogin(); // 自定义登录页面,但提交的url之能是 /login,即mylogin html中action=/login //http.formLogin().loginPage("/mylogin.html").loginProcessingUrl("/login") ; http.formLogin().loginPage("/mylogin.html").usernameParameter("pwd").loginProcessingUrl("/login") ; // 防止跨站攻击功能,自定义登录页面时使用 http.csrf().disable(); // 开启注销功能 回去请求/logout http.logout().logoutSuccessUrl("/a"); } // @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // 正常应该从数据库选择 // 若在数据库中按照此方式写入即可 auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder()) .withUser("username").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2") .and() .withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip3","vip1","vip2"); } } \`\`\` - 自带登录部分,有登录页面,登录controller, - 若要自己定义登录页面,html输入用户名username,pasword,remeberme到/login,注意需要关闭csrf, # 整合Shiro Subject:用户 SecurityManager:管理所有用户 Realm:连接数据 !\[img\](https://img-blog.csdn.net/20151205212625574) !\[img\](https://img-blog.csdn.net/20151205210817437) !\[img\](https://img-blog.csdn.net/20151205213147424) - \`\`\`xml org.apache.shiro shiro-spring 1.4.1 \`\`\` - 配置类 \`\`\`java @Configuration public class ShiroConfig { @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager")DefaultWebSecurityManager securityManager){ ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean(); // 设置管理器 bean.setSecurityManager(securityManager); // 添加内置过滤器,判断当前用户的权限 /\* \* anon:无需认证 \* authc:必须认证 \* user:必须有记住我才能使用 \* perms:有对某个资源的权限才能 \* role:有某个角色才能 \* \*/ Map filter = new LinkedHashMap\<\>(); filter.put("/","anon"); filter.put("/user/\*","authc"); filter.put("/user/add","perms\[user:add\]"); bean.setFilterChainDefinitionMap(filter); // 设置登录url,默认是/login.jsp,里面的登录逻辑还需要自己在controller中写,没有自带 // bean.setLoginUrl("/登录.html"); // bean.setUnauthorizedUrl("/未授权.html"); return bean; } // SecurityManager @Bean public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); // 关联UserRealm securityManager.setRealm(userRealm); return securityManager; } // 创建realm ,需要自定义,此时bean名字就是userRealm @Bean public UserRealm userRealm(){ return new UserRealm(); } } class UserRealm extends AuthorizingRealm{ // @Autowired UserService userservice // 进入页面时调用 //授权 经过后,用户数据库中的权限读取出来,付给subject @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.addStringPermission("user:add"); //拿到对象 Subject subject= SecurityUtils.getSubject(); //User currentUser = (User)subject.getPrincipal() // info.addStringPermissions(user.get权限); 数据库中直接字符串存储 user:add,一般都是按键权限,角色对应表 return info; } // 用户认证,经过后 用户有认证权限 // 登录是调用 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { //连接数据库 UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; // User user = userService.queryUserByName(token.getUsername()); // if(user==null)return null // 密码认证 // return new SimpleAuthenticationInfo("",user.getPassword(),""); return new SimpleAuthenticationInfo("","123456",""); } } \`\`\` - 导入依赖并且写log4j.properties, # 开源Springboot项目 - https://github.com/WinterChenS/my-site,https://demo.winterchen.com/ # Swagger 前后端分离:Vue+SpringBoot - 后端:后端控制,服务层,数据库 - 前端:前端控制,视图层 - 前后端交互 ====》API接口 写代码时前后端需要及时交互,因此后端API需要及时更新 Swagger - Restful API,API文档自动生成 - 可以在线测试 - 支持多种语言 Springboot使用: \`\`\`xml io.springfox springfox-swagger2 2.9.2 io.springfox springfox-swagger-ui 2.9.2 \`\`\` \`\`\`java @Configuration @EnableSwagger2 // 开启swagger2 public class SwaggerConfig { @Bean public Docket docket2() { return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).groupName("B"); } @Bean public Docket docket(){ return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()) // 到这里默认扫描全部接口 // 配置api分组明,配置多个docket .groupName("分组A") // 开启或关闭 swagger2 .enable(true) // 配置扫描的api接口 .select() // RequestHandlerSelectors.any()全部扫描 // RequestHandlerSelectors.none()不扫描 // RequestHandlerSelectors.withMethodAnnotation(RestController.class)注解扫描 .apis(RequestHandlerSelectors.basePackage("top.dean0731.helloworld.controller")) // 过滤路径 .paths(PathSelectors.ant("/user/add/\*\*")) .build(); } private ApiInfo apiInfo(){ return new ApiInfoBuilder().title("WEAF项目整合Swagger") .description("SpringBoot整合Swagger,详细信息......") .version("1.0") .contact(new Contact("啊啊啊啊","blog.csdn.net","aaa@gmail.com")) .license("The Apache License") .licenseUrl("http://www.baidu.com") .build(); } } \`\`\` 访问:http://localhost:/swagger-ui.html # 异步调用 用户执行耗时工作: - 正常情况,直接等待,不能操作 - 多线程,后台主线程返回提示,子线程继续操作,自己实现 - Spingboot的异步操作 @@EnableAsync 启动类加上 \`\`\`java Service @Async public Future doTask1() throws Exception { System.out.println("---任务一---"); long start = System.currentTimeMillis(); Thread.sleep(random.nextInt(10000)); long end = System.currentTimeMillis(); System.out.println("---任务一结束---耗时:"+(end-start)); return new AsyncResult("任务一结束"); } Controller public String async()throws Exception{ System.out.println("---async---"); long start = System.currentTimeMillis(); Future task1 = service.doTask1(); Future task2 = service.doTask2(); Future task3 = service.doTask3(); while (true) { if(task1.isDone()\&\&task2.isDone()\&\&task3.isDone()){ break; } Thread.sleep(1000); } long end = System.currentTimeMillis(); return "all executed time:"+(start-end); } \`\`\` # 整合email 163邮箱授权码直接写密码 \`\`\`xml org.springframework.boot spring-boot-starter-mail \`\`\` \`\`\`yaml spring: mail: username: dean0731qq.com password: xxxxx host: smtp.qq.com properties.mail.smtp.ssl.enable: true \`\`\` \`\`\`java @Service public class EmailServiceImpl implements EmailService{ @Autowired private JavaMailSender mailSender; @Override public void sendSimpleMail(String sendTo, String content) { SimpleMailMessage message = new SimpleMailMessage(); message.setSubject("yyy"); message.setFrom("xxxx"); message.setTo(sendTo); message.setText(content); mailSender.send(message); } @Override public void mimeMail(String sendTo, String content) { MimeMessage m = mailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(m,true,"utf-8"); helper.setSubject("xxx") helper.setFrom("xxxx"); helper.setTo(sendTo); helper.setText("",true); helper.addAttachment("x,jpg",new File("xxxxx")) mailSender.send(m); } } @Controller public class EmailController { @Autowired private EmailService service; @RequestMapping("/simple") @ResponseBody public String sendEmail(){ service.sendSimpleMail("1028968939@qq.com", "测试邮件", "Hello world!"); return "success"; } } \`\`\` \`\`\`java // 模板邮件 @Override public void sendTemplateMail(String sendTo, String title, String infoTemplate) { MimeMessage msg = mailSender.createMimeMessage(); try { //true设置为mutlipart模式 MimeMessageHelper helper = new MimeMessageHelper(msg,true); helper.setFrom("xxx"); helper.setTo(sendTo); helper.setSubject(title); //封装模板数据 Map model = new HashMap\<\>(); model.put("username","dean") //model.put("path", "img/d.png"); //得到模板 Template template = freemarkerConfigurer.getConfiguration().getTemplate(infoTemplate); String html = FreeMarkerTemplateUtils.\*processTemplateIntoString\*(template, model); helper.setText(html,true); } catch (MessagingException \| IOException e) { e.printStackTrace(); } catch (TemplateException e) { e.printStackTrace(); } mailSender.send(msg); } \`\`\` # 定时任务 - @EnableScheduling 开启定时任务 启动类加上 - @Scheduled 什么时候执行 - TaskScheduler 调度者 - TaskExecutor 执行者 \`\`\`java @Service // 要求在某一时间执行 @Scheduled("cron表达式,与linux相同秒:分 时 日 月 周") @Scheduled("\* \* \* \* \* ?")// 每秒一次 public void service(){ } \`\`\` # 整合redis \`\`\`xml org.springframework.boot spring-boot-starter-data-redis \`\`\` \`\`\`yaml spring redis: host: 127.0.0.1 port: 6379 # 集群 cluster: # Springboot 2.0 之后连接池用 lettuce lettuce: \`\`\` \`\`\`java @service @AutoWired @RedisTemplate template public void test(){ // 原生操作 //template.opsForList() //template.opsForZSet() // 常用方法,事物,增删改查等 // 获取链接 //RedisConnect con = template.getConnectionFactory().getConnection(); //con.flushDb(); //con.flushAll() template.opsValue().set('key','value') template.opsValue().get('key') // 真实场景,对象写入redis需要序列化,所以 model一般都回实现序列化接口 } \`\`\` Springboot中的RedisTemplate完成了自己的序列化, 不能识别,因为RedisTemplate的序列化方式不完善,是JDK自己的序列化,此时redis查看的字符会转义 要自己定义,解决问题, \`\`\`java @Configuration public class RedisConfig { @Bean public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory){ // 为了开放方便 使用 string,object RedisTemplate template = new RedisTemplate\<\>(); template.setConnectionFactory(redisConnectionFactory); StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); Jackson2JsonRedisSerializer jack =new Jackson2JsonRedisSerializer(Object.class); // 对象转义 ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); // om.activateDefaultTyping(); 2.10之后使用这个 jack.setObjectMapper(om); // 设置key的序列化方式 template.setKeySerializer(stringRedisSerializer); template.setHashKeySerializer(stringRedisSerializer); // 设置value的序列化方式 template.setValueSerializer(jack); template.setHashValueSerializer(jack); template.afterPropertiesSet(); return template; } } \`\`\` # zookeeeper - 分布式应用程序协调服务 - 是hadoop与hbase的重要组件 - 为分布式应用提供一致性服务的软件 - 配置维护 - 域名服务 - 分布式同步 - 组服务 ,例如服务的注册与发现 windows下使用: - 下载 - 运行 \~/bin/zKserver.cmd - java环境要配置好classpath等等 - conf/zoo_simple.cfg 复制到conf/zoo.cfg 默认端口2181 - \~/bin/zkCli.cmd 客户端连接 - \`\`\`shell ls / create /firstname 123 # 创建节点 get /fristname # 查看节点内容 \`\`\` # 分布式 - 网络之上的软件系统 - 原来的分布式,全部的业务放在一个机器上,机器之间安全相同,nginx做负载均衡 - 有些流程很简单,有些复杂 - 机器利用率不高 !\[image-20200817155613692\](https://i.loli.net/2020/08/17/DISZnHsgpcdAuFW.png) 小型网站 !\[img\](https://i.loli.net/2020/08/17/dJQkO9AsemfTaZw.png) 现在的小型网站,功能呢模块无法利用 !\[img\](https://i.loli.net/2020/08/17/OwSovyTHtAZXisx.png) 分布式架构,提取公共模块 !\[img\](https://i.loli.net/2020/08/17/XAxcZj7u1UvqmHG.png) 现在流行的分布式 !\[img\](https://i.loli.net/2020/08/17/Va4h6sI7lbpQDKB.png) 基础就是微服务架构 Dubbo + Zookeeper +Springboot !\[img\](https://i.loli.net/2020/08/17/Mx19qWhsIdNa5y6.png) # RPC - 远程过程调用 - 电脑一A方法调用电脑二B方法 - 核心模块 - 通信 - 序列化 # dubbo - 高性能,轻量级 javaRPC框架 - 面向接口的远程方法调用 - 智能容错与负载均衡 - 服务自动注册与发现,使用zookeeper - !\[img\](https://i.loli.net/2020/08/17/oWC7Nhl2fKBQV6m.png) - 使用监控管理后台dubbo-admin,可以不要 - github下载,是个Springboot项目 - 修改配置文件application.properties - 按需要修改默认端口 - 后台端口7001 root,root - dubbo.registry.address=zookeeper://ip:port - 打包该项目 mvn clean package -Dmaven.test.skip=true - 生成jar 服务提供者:可以理解为一些后端项目APi接口 \`\`\`xml org.apache.dubbo dubbo-spring-boot-starter 2.7.7 com.github.sgroschupf zkclient 0.1 org.apache.curator curator-framework 5.1.0 org.apache.curator curator-recipes 5.1.0 org.apache.zookeeper zookeeper 3.6.1 org.slf4j slf4j-log4j12 \`\`\` \`\`\`yaml dubbo: application: name: provider-server1 registry: address: zookeeper://127.0.0.1:2181 scan: base-packages: top.dean0731.helloworld.service # 服务 \`\`\` \`\`\`java //service @DubboService // dubbo的service ,启动时可以被扫描注册到注册中心 @Component // spring 的万能注解 public class UserserviceImpl implement UserService{ public String service1(){} } public interface UserService{ public String service1(); } \`\`\` - 启动zookeeper 端口2181 - 启动dubbo监控 端口7001 - 启动项目服务端dubbo,此时该服务的访问地址是 ip:20880 - 注意此时暴露在外面的是service,不是controller,要访问controller还是8080 - 启动customer 客户端使用: \`\`\`xml 同上 \`\`\` \`\`\`yaml dubbo: application: name: consumer-1 registry: address: zookeeper://127.0.0.1:2181 scan: \`\`\` \`\`\`java @DubboService //dubbo的service 放到容器中 public class 调用Service{ // @Reference //dubbo的reference UserService service; //路径相同建立UserService类或者使用pom坐标 public void 使用(){ String s= service.service1() } } \`\`\` # 日志管理 - (架包默认添加是logback) 若想更改logback:加入全局配置文件 - 其他日志系统使用时只用把配置问价放在src下即可,不用全局配置文件 - 默认info级别信息 - Trace,debug,info,warn,error,fatal,off从低到高:设置为warn,低与warn的不会输出 - root日志以warn级别即以上输出 - springframework.web日主以debug级别输出 \`\`\`properties Logging.level.root=warn Logging.level.org.springframework.web=debug \`\`\` ## 自定义日志配置 \`\`\`xml logback ERROR --\> %d{HH:mm:ss.SSS}%contextName\[%thread\]%-5level%logger{36} -%msg%n ${log.path} ${log.path}/logback.%d{yyyy-MM-dd}.log %d{HH:mm:ss.SSS}%contextName\[%thread\]%-5level%logger{36} -%msg%n \`\`\` ## 使用log4j日志管理,去掉logback \`\`\`xml org.springframework.boot spring-boot-starter org.springframework.boot spring-boot-starter-logging org.springframework.boot spring-boot-starter-log4j 1.3.8.RELEASE \`\`\` 2,log4j.properties \`\`\`properties ############# # 输出到控制台 ############# # log4j.rootLogger日志输出类别和级别:只输出不低于该级别的日志信息DEBUG \< INFO \< WARN \< ERROR \< FATAL # WARN:日志级别 CONSOLE:输出位置自己定义的一个名字 logfile:输出位置自己定义的一个名字 log4j.rootLogger=WARN,CONSOLE,logfile # 配置CONSOLE输出到控制台 log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender # 配置CONSOLE设置为自定义布局模式 log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout # 配置CONSOLE日志的输出格式 \[frame\] 2019-08-22 22:52:12,000 %r耗费毫秒数 %p日志的优先级 %t线程名 %C所属类名通常为全类名 %L代码中的行号 %x线程相关联的NDC %m日志 %n换行 log4j.appender.CONSOLE.layout.ConversionPattern=\[frame\] %d{yyyy-MM-dd HH:mm:ss,SSS} - %-4r %-5p \[%t\] %C:%L %x - %m%n ################ # 输出到日志文件中 ################ # 配置logfile输出到文件中 文件大小到达指定尺寸的时候产生新的日志文件 log4j.appender.logfile=org.apache.log4j.RollingFileAppender # 保存编码格式 log4j.appender.logfile.Encoding=UTF-8 # 输出文件位置此为项目根目录下的logs文件夹中 log4j.appender.logfile.File=logs/root.log # 后缀可以是KB,MB,GB达到该大小后创建新的日志文件 log4j.appender.logfile.MaxFileSize=10MB # 设置滚定文件的最大值3 指可以产生root.log.1、root.log.2、root.log.3和root.log四个日志文件 log4j.appender.logfile.MaxBackupIndex=3 # 配置logfile为自定义布局模式 log4j.appender.logfile.layout=org.apache.log4j.PatternLayout log4j.appender.logfile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %F %p %m%n ########################## # 对不同的类输出不同的日志文件 ########################## # club.bagedate包下的日志单独输出 log4j.logger.club.bagedate=DEBUG,bagedate # 设置为false该日志信息就不会加入到rootLogger中了 log4j.additivity.club.bagedate=false # 下面就和上面配置一样了 log4j.appender.bagedate=org.apache.log4j.RollingFileAppender log4j.appender.bagedate.Encoding=UTF-8 log4j.appender.bagedate.File=logs/bagedate.log log4j.appender.bagedate.MaxFileSize=10MB log4j.appender.bagedate.MaxBackupIndex=3 log4j.appender.bagedate.layout=org.apache.log4j.PatternLayout log4j.appender.bagedate.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %F %p %m%n \`\`\` ## 自定义消息转换器 \`\`\`java @Bean private StringHttpMessageConverter converter(){ StringHttpMessageConverter converter = new StringHttpMessageConverter(Charset.\*forName\*("utf-8")); return converter; } \`\`\` # 使用FastJson解析json 配置FastJson 1,在MyWebConfig中重写 \`\`\`java @Override public void configureMessageConverters(List\> converters) { //创建fastjson消息解析器 FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter(); //创建fastjson的配置对象 FastJsonConfig config = new FastJsonConfig(); //对json数据进行格式化 config.setSerializerFeatures(SerializerFeature.PrettyFormat); converter.setFastJsonConfig(config); converters.add(converter); } @Bean public HttpMessageConverters fastJsonMessageConverter(){ //创建fastjson消息解析器 FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter(); //创建fastjson的配置对象 FastJsonConfig config = new FastJsonConfig(); //对json数据进行格式化 config.setSerializerFeatures(SerializerFeature.PrettyFormat); converter.setFastJsonConfig(config); return new HttpMessageConverters(converter); } \`\`\` # 现在和未来 回顾以前:架构 - 三层架构MVC - 解耦合 - 开发框架 - spring - IOC - AOP - 切面,动态代理 - 不影响业务情况下增加功能 - 日志,事物等 - 轻量级java开源容器 - 解决开发复杂性 - Springboot - 不是新东西,就是Spring的升级版 - 新一代JAVAEE开发标准,开箱即用 - 自动配置了很多 - 微服务架构 - 模块化,功能化 - 原来是所有功能在一起,签到,支付,娱乐 - 人多, - 横向增加机器 - 签到多,支付少-----》模块化 - 微服务架构问题,因为网络不可靠 - 服务很多,客户端如何访问?API网关,服务路由 - 服务很多,服务之间如何通信 ,RPC框架,异步调用 - 服务很多,如何治理 ,服务注册与发现,高可用 - 服务挂了,咋办 ?熔断机制,服务降级 - 解决方案 - SpringCloud,生态圈,解决上边4个问题,SpringCloud基于SpringBoot - 方案一:SpringCloud netfix ,一站式解决方案,但2018年底无限期不再维护 - api网关 zuul组件 - Feign --》httpclient---》http的通信方式,同步阻塞 - 服务注册与发现:Eureka - 熔断机制:hystrix - 方案二:Apache Dubbo zookeeper,本来是不维护了,后来又维护了, - API:没有,第三方组件 - dubbo,高性能RPC框架 - 服务注册与发现,zookeeper; - 没有,借助了hystrix dubbo3.0还为出现,预览中,有很多新东西 - 方案三:SpringCloud Alibaba,一站式解决方案 - 服务网格,下一代微服务架构 Server mesh - 对应方案:istio Springboot视频地址:https://www.bilibili.com/video/BV1PE411i7CV