pytest入坑到放棄2--pytest.main()
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包
<!-- 父級依賴 --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.3.RELEASE</version> </parent> <!--啟動器:web環境下的依賴, 使用springmvc spring的jar,tomcat等 --> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> <!--打包外掛--> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
# properties格式
# 配置檔案
# 更改埠號
server.port=8081
debug: true
# 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]
@Component @ConfigurationProperties(prefix = "student") @Validated //資料校驗 public class Student { @Email("郵箱格式錯誤") private String email; }
自定義啟動圖示(banner)
http://patorjk.com/software/taag
resources下複製儲存為banner.txt
常用maven命令
- clean:清理
- package:打包jar或war
示例
@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
- 核心依賴在父工程中
-
啟動器
-
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>
-
需要什麼功能就匯入對應啟動器
-
-
主程式
@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) 自動配置匯入選擇
- AutoConfigurationPackage:自動配置包
- SpringBootConfiguration:springboot配置類
- Configuration:spring配置類
- Component:這一是spring
- Configuration:spring配置類
- ComponentScan 掃描啟動類同級別的包
- EnableAutoConfiguration(exclude={xxxConfiguration.class,yyy.Configuartion})啟動自動配置
- SpringBootApplication包含比較重要的幾個
多檔案配置
classpath:
- java資料夾
- resources資料夾
配置檔案位置:
- resources下 優先順序最低
- resources/config/下 優先順序較低
- 根目錄下 優先順序次高
- 根目錄/config/下 優先順序最高
多配置檔案:
-
預設的還是原名
-
建立其他的application-dev.properties
-
測試開發時,每次分別使用不同properties,在主properties中指定: spring.profiles.active=dev ,指定配置檔案
-
# --- 可用作分割,不用多個檔案 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/下邊
-
<dependency> <groupId>org.webjars</groupId> <artifactId>jquery</artifactId> <version>3.5.1</version> </dependency>
-
-
不自己配置時:
- 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
自定義配置類
讀取配置時會看是否有使用者自定義配置,有的話使用使用者的,
對於有的配置可有多個,例如檢視解析器,就結合使用
// 擴充套件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;
}
}
}
攔截器
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,對應錯誤會找到對應的
資料來源配置
<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>
<!-- 引入依賴-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.21</version>
</dependency>
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
@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();
}
@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<StatViewServlet> bean = new ServletRegistrationBean<>(new StatViewServlet(),"/druid/*");
// 後臺登入,賬號密碼
HashMap<String,String> 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<String,String> initParameters = new HashMap<>();
// 不過濾
initParameters.put("exclusions","*.js,*.css,/durid/*");
return bean;
}
}
資料庫JDBC
//jdbc ,有dao
@Autowired
JdbcTemplate jdbcTemplate;
@RequestMapping("/getAll")
public List<Map<String,Object>> userList(){
List<Map<String,Object>> list = jdbcTemplate.queryForList("select * from user");
return list;
}
整合mybatis(xml方式)
匯入依賴
<!-- 不是springboot官方的,是mybatis自己的-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
配置yaml
mybatis:
type-aliases-package: top.dean0731.model
mapper-locations: classpath:mybatis/mapper/*xml
mapper 檔案
@Mapper
@Repository
public interface EmployeeMapper {
List<Employee> queryEmployeeList();
Employee queryEmployerById();
int addEmployee(Employee employee);
int updateEmployee(Employee employee);
int deleteEmployee(int id);
}
//mapper 代替dao,Resource下mybatis/mapper/下建立配置檔案
<?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="top.dean0731.mapper.EmployeeMapper">
<select id="queryEmployeeList" resultType="Employee">
select * from Employee
</select>
</mapper>
整合mybatis(註解方式)
@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思想
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
@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:連線資料
-
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.4.1</version>
-
配置類
@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<String,String> 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專案
Swagger
前後端分離:Vue+SpringBoot
- 後端:後端控制,服務層,資料庫
- 前端:前端控制,檢視層
- 前後端互動 ====》API介面
寫程式碼時前後端需要及時互動,因此後端API需要及時更新
Swagger
- Restful API,API文件自動生成
- 可以線上測試
- 支援多種語言
Springboot使用:
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
@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","[email protected]"))
.license("The Apache License")
.licenseUrl("http://www.baidu.com")
.build();
}
}
訪問:http://localhost:/swagger-ui.html
非同步呼叫
使用者執行耗時工作:
- 正常情況,直接等待,不能操作
- 多執行緒,後臺主執行緒返回提示,子執行緒繼續操作,自己實現
- Spingboot的非同步操作
@@EnableAsync 啟動類加上
Service
@Async
public Future<String> 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<String>("任務一結束");
}
Controller
public String async()throws Exception{
System.out.println("---async---");
long start = System.currentTimeMillis();
Future<String> task1 = service.doTask1();
Future<String> task2 = service.doTask2();
Future<String> 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郵箱授權碼直接寫密碼
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
spring:
mail:
username: dean0731qq.com
password: xxxxx
host: smtp.qq.com
properties.mail.smtp.ssl.enable: true
@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("<html</html>",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("[email protected]", "測試郵件", "Hello world!");
return "success";
}
}
// 模板郵件
@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<String, Object> 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 執行者
@Service
// 要求在某一時間執行
@Scheduled("cron表示式,與linux相同秒:分 時 日 月 周")
@Scheduled("* * * * * ?")// 每秒一次
public void service(){
}
整合redis
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
spring
redis:
host: 127.0.0.1
port: 6379
# 叢集
cluster:
# Springboot 2.0 之後連線池用 lettuce
lettuce:
@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檢視的字元會轉義
要自己定義,解決問題,
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
// 為了開放方便 使用 string,object
RedisTemplate<String,Object> 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 客戶端連線
-
ls / create /firstname 123 # 建立節點 get /fristname # 檢視節點內容
-
分散式
-
網路之上的軟體系統
-
原來的分散式,全部的業務放在一個機器上,機器之間安全相同,nginx做負載均衡
- 有些流程很簡單,有些複雜
- 機器利用率不高
小型網站
現在的小型網站,功能呢模組無法利用
分散式架構,提取公共模組
現在流行的分散式
基礎就是微服務架構
Dubbo + Zookeeper +Springboot
RPC
- 遠端過程呼叫
- 電腦一A方法呼叫電腦二B方法
- 核心模組
- 通訊
- 序列化
dubbo
- 高效能,輕量級 javaRPC框架
- 面向介面的遠端方法呼叫
- 智慧容錯與負載均衡
- 服務自動註冊與發現,使用zookeeper
- 使用監控管理後臺dubbo-admin,可以不要
- github下載,是個Springboot專案
- 修改配置檔案application.properties
- 按需要修改預設埠
- 後臺埠7001 root,root
- dubbo.registry.address=zookeeper://ip:port
- 打包該專案 mvn clean package -Dmaven.test.skip=true
- 生成jar
服務提供者:可以理解為一些後端專案APi介面
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.7</version>
</dependency>
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>5.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>5.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.6.1</version>
<exclusions>
<!-- 與springboot日誌衝突,排除-->
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
dubbo:
application:
name: provider-server1
registry:
address: zookeeper://127.0.0.1:2181
scan:
base-packages: top.dean0731.helloworld.service # 服務
//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
客戶端使用:
同上
dubbo:
application:
name: consumer-1
registry:
address: zookeeper://127.0.0.1:2181
scan:
@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級別輸出
Logging.level.root=warn
Logging.level.org.springframework.web=debug
自定義日誌配置
<?xml version="1.0" encoding="utf-8"?>
<!-- 發生改變時:重新載入, 每間隔60s掃描一下,是否改變 ,debug:列印內部日誌資訊 -->
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!-- 上下文名字 -->
<contextName>logback</contextName>
<!-- 定義變數 -->
<property name="log.path" value="G:\\soft_doc\\Myeclispe_Project\\info.log"></property>
<!-- 輸出到控制檯 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<!-- 預設日誌過濾器 -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>ERROR</level>
</filter> -->
<encoder>
<pattern>%d{HH:mm:ss.SSS}%contextName[%thread]%-5level%logger{36} -%msg%n</pattern>
</encoder>
</appender>
<!-- 輸出到文字 -->
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${log.path}</file>
<!-- 日誌問價切割策略 :每天一個日誌-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${log.path}/logback.%d{yyyy-MM-dd}.log</fileNamePattern> </rollingPolicy>
<encoder>
<pattern>%d{HH:mm:ss.SSS}%contextName[%thread]%-5level%logger{36} -%msg%n
</pattern>
</encoder>
</appender>
<root level="info">
<appender-ref ref="console"/>
<appender-ref ref="file"/>
</root>
<!-- logback為java中的包單獨設定日誌級別 -->
<logger name="com.dzf.controller"/>
<!-- 具體到類:設定新的級別,是否向上級傳遞列印資訊 -->
<logger name="com.dzf.controller.SpringController" level="warn" additivity="false"> <appender-ref ref="console"/>
</logger>
</configuration>
使用log4j日誌管理,去掉logback
<!-- 取出日誌檔案logback -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 新增loj4j -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j</artifactId>
<version>1.3.8.RELEASE</version>
</dependency>
2,log4j.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
自定義訊息轉換器
@Bean
private StringHttpMessageConverter converter(){
StringHttpMessageConverter converter = new
StringHttpMessageConverter(Charset.*forName*("utf-8"));
return converter;
}
使用FastJson解析json
配置FastJson
1,在MyWebConfig中重寫
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> 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開發標準,開箱即用
- 自動配置了很多
- spring
-
微服務架構
-
模組化,功能化
- 原來是所有功能在一起,簽到,支付,娛樂
- 人多,
- 橫向增加機器
- 簽到多,支付少-----》模組化
-
微服務架構問題,因為網路不可靠
- 服務很多,客戶端如何訪問?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