SpringBoot2
微服務的概念
微服務就是將一個大的系統拆分成多個子系統,然後通過REST風格的請求將他們整合起來,進一步簡化了分散式系統的開發
SpringBoot2的特點
- 約定大於配置,通過引入xx-starter加上自定義的配置檔案就可以整合某個元件的java客戶端
- 內建tomcat/undertow
- 提供快速的測試環境
為什麼要學這個
每天都在用SpringBoot缺不知道其中的原理,典型的日用而不知。一旦出現開發的問題,就是一頓部落格亂找,很久也解決不了問題 所以,理解原理很重要
Bean的宣告週期
1.Spring通過配置,如@SpringBootApplication或@ComponentScan定義的路徑(預設為當前包和子包)找到帶有@Component的類
2.解析類定義,把Bean定義釋出到Ioc容器中,注意:是定義,不是例項
3.Ioc容器裝載Bean的定義
4.建立Bean的例項物件
5.開始掃描@Autowired注入各類資源
踩坑
@Service
public class Service{
@Autowired
public String kafkaHost;
public KafkaAppender;
public Service(){
KafkaAppender = new KafkaAppender(kafkaHost);
}
}
複製程式碼
注意,當Service被初始化時,會呼叫構造器,此時kafkaHost還沒被Autowired注入,所以這個時候kafkaHost為null
Spring註解說明
Spring註解之Bean註解:
@Configuration
public class AppConfig {
@Bean(name="user"}
public User initUser () {
User user= new User ();
user.setId(100) ;
user.setUserName();
return user;
}
}
@Service
public class System{
@Autowired
private User user;
}
複製程式碼
@Bean表示將initUser返回的user裝配到Ioc中,而且該bean的name為user。如果沒有定義name,則bean的name為方法名(initUser)
@ComponentScan與@Component
@Component("user")
public class User {
private id;
private String userName;
private String note;
}
@Service
public class System{
@Autowired
private User user;
}
複製程式碼
注意事項
- @Component註解作用域預設為singleton
- @Component表名這個類將被Ioc裝配,而且該bean的name為user,如果沒有顯示定義name,則以類名第一個字母小寫作為bean的name
- @Component使用在不確定哪一個層的時候使用,可以作用在任何層次,把普通pojo例項化到spring容器
- 不推薦使用@Component註解,而應該使用它的擴充套件,如@Service、@Repository
業務元件的註釋
- @Component 沒有明確角色的元件
- @Service 在業務邏輯層(Service層)使用
- @Repository 在資料訪問層(dao層)使用
- @Controller 用於標註控制層元件
- @RestController 純REST風格的控制器
@Service
@Service註解作用在類上
@Service註解作用域預設為singleton
使用註解配置和類路徑掃描時,被@Service註解標註的類會被Spring掃描並註冊為Bean
@Service註解用於標註業務的邏輯元件,即服務元件元件
複製程式碼
@Repository
@Repository註解作用在類上
@Repository註解作用域預設為singleton
使用註解配置和類路徑掃描時,被@Repository註解標註的類會被Spring掃描並註冊為Bean
@Repository註解用於標註資料訪問元件,即DAO元件
@Repository註解的作用不只是將類識別為Bean,同時它還能將所標註的類中丟擲的資料訪問異常封裝為 Spring 的資料訪問異常型別
複製程式碼
@Controller
@Controller註解作用在類上
使用註解配置和類路徑掃描時,被@Controller註解標註的類會被Spring掃描並註冊為Bean
@Controller用於標註Web中控制層元件
被@Controller標註的類負責處理由DispatcherServlet分發的請求,
它把使用者請求的資料經過業務處理層處理之後封裝成一個Model ,然後再把該Model返回給對應的View進行展示
@Controller和@RequestMapping、@RequestParam等一些註解共同處理URL的對映
複製程式碼
@ComponentScan意味著掃描當前註釋類所在的包和子包
@SpringBootApplication
@SpringBootApplication預設包含了@ComponentScan
@Autowired、@Primary、@Qualifier
Spring最常用的註解,根據型別找到對應的Bean進行注入,也就是getBeanByType()
- 首先根據型別找到對應型別的Bean,如果不唯一,則按照Bean名稱進行匹配,如果還找不到,就拋異常
- 當對應型別的Bean有多個時,@Primary告訴Ioc容器,優先使用帶有@Primary標識的Bean
public interface User {
}
@Component
@Primary
public class Man implements {
}
@Component
public class Woman implements {
}
public class System{
@Autowired
private User user;
這裡裝配的是Woman
}
複製程式碼
- @Qualifier告訴Ioc容器按照型別和名稱去找到對應的Bean
public interface User {
}
@Component
@Primary
public class Man implements {
}
@Component
@Primary
public class Woman implements {
}
public class System{
@Autowired
@Qualiefier("man")
private User user;
這裡裝配的是Man
public void heiheihei(@Autowired @Qualiefier("man") User user){};
}
複製程式碼
@Value與@ConfigurationProperties
從配置檔案中獲取屬性
@Component
@ConfigurationProperties(prefix = "microservice.quickstart")
public class User{
@Value('${user.name}')
private String userName;
//讀取配置檔案中的microservice.quickstart.user.name配置
}
複製程式碼
多環境配置下的啟動
按照工程建立
- application.properties
- application-dev.properties
- application-test.properties
- application-prd.properties 啟動時新增命令作為引數 java -jar xx.jar -Dpsirng.profiles.active=dev java -jar xx.jar -Dpsirng.profiles.active=test java -jar xx.jar -Dpsirng.profiles.active=prd
@Scope作用在類上和方法上
@Scope用來配置Bean的作用域,有以下幾種
singleton單例模式
Spring 容器中有且只有一個Bean例項,只要Spring容器不銷燬或退出,該Bean例項就會一直存活
prototype原型模式
每次獲取Bean的時候會有一個新的例項,Spring容器不能對返回Bean例項的整個生命週期負責
request模式
request只適用於Web程式,每一次HTTP請求都會產生一個新的bean, 同時該bean僅在當前HTTP request內有效,當請求結束後,該物件的生命週期即告結束
session模式
session只適用於Web程式,session作用域表示該針對每一次HTTP請求都會產生一個新的bean, 同時該bean僅在當前HTTP session內有效
application模式
application只適用於Web程式,全域性作用域
@Conditional(TestCondition.class)
這句程式碼可以標註在類上面,表示該類下面的所有@Bean都會啟用配置,也可以標註在方法上面,只是對該方法啟用配置。
@ConditionalOnBean(僅僅在當前上下文中存在某個物件時,才會例項化一個Bean) @ConditionalOnClass(某個class位於類路徑上,才會例項化一個Bean) @ConditionalOnExpression(當表示式為true的時候,才會例項化一個Bean) @ConditionalOnMissingBean(僅僅在當前上下文中不存在某個物件時,才會例項化一個Bean) @ConditionalOnMissingClass(某個class類路徑上不存在的時候,才會例項化一個Bean) @ConditionalOnNotWebApplication(不是web應用)
spring原始碼閱讀
@EnableWebMvc、WebMvcConfigurationSupport和WebMvcConfigurationAdapter三者之間的區別是什麼 @EnableWebMvc註解的類等於extends WebMvcConfigurationSupport 但是沒有重寫任何方法 SpringBoot WebMVC的自動配置資訊都在WebMvcAutoConfiguration這個類中,我們看他的原始碼
@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
@AutoConfigureOrder(-2147483638) //Bean的初始化順序
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class, ValidationAutoConfiguration.class})
public class WebMvcAutoConfiguration {
複製程式碼
其中@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})的意思是,當工程中沒有WebMvcConfigurationSupport 時,才會使用WebMvc的自動配置;我們一般會繼承WebMvcConfigurationSupport來自定義配置類, 但是一旦繼承WebMvcConfigurationSupport後就會出現新的問題: 會發現Spring Boot的WebMvc自動配置失效,具體表現比如訪問不到靜態資源(js,css等)了。
攔截器原理
動態代理
上海體育公園有很多大爺大媽相親,你要去尋找女朋友。這時,你就問大媽:女兒喜歡什麼呀,大媽可能會替她回答。 當然,大媽覺得你髮際線太高,他也可以直接拒絕。這時,這個大媽就是她女兒的代理
JDK中的使用方式
JDK提供了類Proxy的靜態方法:newProxyInstance.
public static Object newProxyInstance(ClassLoader var0, Class<?>[] var1, InvocationHandler var2) throws IllegalArgumentException
這裡的invocationHandler是一個介面InvocationHandler物件,定義了invoke方法,這個方法就是實現代理物件邏輯的 通過target\method\args就能夠用反射方法執行了
具體見:ProxyBean.java[請學會用IDEA找到對應名字的類]
AOP約定流程
按照我們上面實現的程式碼,可以看到,AOP是一種規範化的約定,我們按照這種約定來使用,就可以實現動態代理 aop-principle.png
攔截器使用AOP的約定
spring-intercetor.png
Spring中使用@AspectJ
Spring AOP使用@AspectJ對方法進行攔截,所以,我們要先確定什麼地方需要AOP,也就是連線點 有了連線點後,我們需要一個切面,用來描述流程的織入 請看案例:
MyAspect.java
Myabits中的資料庫事務
@Transactional可以放在方法上,也可以放在類上 如果放在類上,則該類的所有方法都預設帶了@Transactional 案例請檢視
com.liuyiling.microservice.api.controller.DataBaseController.transactional
注意事項
- @Transactional必須加在public方法上,否則CGlib代理會找不到
- 正確的設定@Transactional 的 isolation 屬性
事務的隔離度,預設值採用 DEFAULT
- 事務必須註解在非自呼叫方法上,下面面這個例子事務將不會被呼叫
@Service
public class OrderService {
private void insert() {
insertOrder();
}
@Transactional
public void insertOrder() {
}
}
複製程式碼
- 可以指定事務的回滾條件
預設情況下,如果在事務中丟擲了未檢查異常(繼承自 RuntimeException 的異常)或者 Error,則 Spring 將回滾事務;除此之外,Spring 不會回滾事務。 如果在事務中丟擲其他型別的異常,並期望 Spring 能夠回滾事務,可以指定 rollbackFor。例: @Transactional(propagation= Propagation.REQUIRED,rollbackFor= MyException.class)