【原創】003 | 搭上基於SpringBoot事務思想實戰專車
前言
如果這是你第二次看到師長,說明你在覬覦我的美色!
點贊+關注再看,養成習慣
沒別的意思,就是需要你的窺屏_
專車介紹
該趟專車是開往基於Spring Boot事務思想實戰的專車,在上一篇 搭上SpringBoot事務原始碼分析專車[1]中我們詳細介紹了Spring Boot事務實現的原理,這一篇是基於上一篇的實戰。
在實戰之前,我們再次回顧下上篇文章講解的重點:
- 後置處理器:對Bean進行攔截並處理
- 切面:由切點和通知組成
- 切點:用於匹配符合的類和方法
- 通知:用於代理處理
專車問題
- 如何利用後置處理器對Bean進行攔截並處理?
- 如何定義切面?
- 如何定義切點?
- 如何定義通知?
- 如何實現自動配置?
專車分析
實現是以Spring Boot為基礎,需要新增如下依賴
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
按照如上提到的問題依次定義
定義bean後置處理器,特別注意,如果專案中使用到了事務特性,就不需要重複定義
/**
* 一定要宣告InfrastructureAdvisorAutoProxyCreator,用於實現bean的後置處理
*
* @return
*/
@Bean
public InfrastructureAdvisorAutoProxyCreator infrastructureAdvisorAutoProxyCreator() {
return new InfrastructureAdvisorAutoProxyCreator();
}
定義切面
public class BeanFactorySystemLogAdvisor extends AbstractBeanFactoryPointcutAdvisor {
/**
* 定義切點
*/
private final SystemLogPointcut point = new SystemLogPointcut();
@Override
public Pointcut getPointcut() {
return this.point;
}
}
定義切點
public class SystemLogPointcut extends StaticMethodMatcherPointcut {
@Override
public boolean matches(Method method, Class<?> targetClass) {
// 查詢類上@SystemLog註解屬性
AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
targetClass, SystemLog.class, false, false);
if (Objects.nonNull(attributes)) {
return true;
}
// 查詢方法上@SystemLog註解屬性
attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
method, SystemLog.class, false, false);
return Objects.nonNull(attributes);
}
}
定義通知
@Slf4j
public class SystemLogInterceptor implements MethodInterceptor, Serializable {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Method method = invocation.getMethod();
String className = method.getDeclaringClass().getSimpleName();
String methodName = method.getName();
log.info("======[" + className + "#" + methodName + " method begin execute]======");
Arrays.stream(invocation.getArguments()).forEach(argument -> log.info("======[execute method argument:" + argument + "]======"));
Long time1 = Clock.systemDefaultZone().millis();
Object result = invocation.proceed();
Long time2 = Clock.systemDefaultZone().millis();
log.info("======[method execute time:" + (time2 - time1) + "]======");
return result;
}
}
自動配置
@Configuration
public class ProxySystemLogConfiguration {
/**
* 定義切面
* 此處一定要指定@Role註解
*
* @return
*/
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
@Bean
public BeanFactorySystemLogAdvisor beanFactorySystemLogAdvisor() {
BeanFactorySystemLogAdvisor advisor = new BeanFactorySystemLogAdvisor();
advisor.setAdvice(systemLogInterceptor());
return advisor;
}
/**
* 定義通知
*
* @return
*/
@Bean
public SystemLogInterceptor systemLogInterceptor() {
return new SystemLogInterceptor();
}
/**
* 一定要宣告InfrastructureAdvisorAutoProxyCreator,用於實現bean的後置處理
*
* @return
*/
@Bean
public InfrastructureAdvisorAutoProxyCreator infrastructureAdvisorAutoProxyCreator() {
return new InfrastructureAdvisorAutoProxyCreator();
}
}
定義註解
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SystemLog {
}
專車整合業務
定義控制器
@RestController
public class SystemLogController {
@Autowired
private SystemLogService systemLogService;
@GetMapping("/log")
public String hello(@RequestParam("name") String name) throws InterruptedException {
return systemLogService.log(name);
}
}
定義業務方法
@Slf4j
@Service
public class SystemLogService {
@SystemLog
public String log(String name) throws InterruptedException {
log.info("執行業務方法");
TimeUnit.SECONDS.sleep(1);
return "hello " + name;
}
}
定義啟動類
@SpringBootApplication
public class TransactionImitateApplication {
public static void main(String[] args) {
SpringApplication.run(TransactionImitateApplication.class, args);
}
}
訪問
檢視控制檯
2019-08-23 11:13:36.029 INFO 23227 --- [nio-8080-exec-1] c.b.example.config.SystemLogInterceptor : ======[SystemLogService#log method begin execute]======2019-08-23 11:13:36.030 INFO 23227 --- [nio-8080-exec-1] c.b.example.config.SystemLogInterceptor : ======[execute method argument:advisor]======2019-08-23 11:13:36.038 INFO 23227 --- [nio-8080-exec-1] c.boot.example.service.SystemLogService : 執行業務方法2019-08-23 11:13:37.038 INFO 23227 --- [nio-8080-exec-1] c.b.example.config.SystemLogInterceptor : ======[method execute time:1004]======
可以看到透過模擬@Transaction註解的實現方式,完成了日誌切面功能。
專車總結
- 首先我們需要定義一個Bean後置處理器,用於攔截處理Bean
- 然後定義切面,在切面中定義切點
- 切點中實現切入的邏輯,比如此處我們的實現邏輯就是查詢類或方法上是否含有@SystemLog註解
- 定義通知,完成代理工作
- 自動裝配,將我們的切面、通知、Bean後置處理器宣告在配置類中
- 整合業務
專車回顧
回顧下開頭的五個問題:
- 如何利用後置處理器對Bean進行攔截並處理?直接在配置類中宣告後置處理器
- 如何定義切面?繼承AbstractBeanFactoryPointcutAdvisor,並在配置類中中宣告
- 如何定義切點?繼承StaticMethodMatcherPointcut,實現matches方法
- 如何定義通知?實現MethodInterceptor介面,實現invoke方法
- 如何實現自動配置?自定義配置類,宣告所有需要加入容器的Bean
最後
師長,【java進階架構師】號主,短短一年在各大平臺斬獲15W+程式設計師關注,專注分享Java進階、架構技術、高併發、微服務、BAT面試、redis專題、JVM調優、Springboot原始碼、mysql最佳化等20大進階架構專題。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/3486/viewspace-2824469/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 實戰與原理:如何基於RocketMQ實現分散式事務?MQ分散式
- 原創:oracle 事務總結Oracle
- 【原創】Mysql中事務ACID實現原理MySql
- 基於RocketMQ實現分散式事務MQ分散式
- [DB2]原創--實戰式體驗事務隔離級別之UR篇DB2
- 基於事務日誌還原到時間點
- 分散式事務實戰分散式
- 【原創】Oracle 事務探索與例項(二)Oracle
- 【原創】 Oracle 事務探索與例項(一)Oracle
- springboot專案-宣告式事務失效Spring Boot
- laravel基於remote model思想實現快速服務化(入門篇)LaravelREM
- 基於webpack4.x專案實戰Web
- SpringBoot2 基礎案例(12):基於轉賬案例,演示事務管理操作Spring Boot
- SpringBoot實戰之事務抽象Spring Boot抽象
- MySQL 中基於 XA 實現的分散式事務MySql分散式
- spring基於註解配置實現事務控制Spring
- Laravel基於reset機制實現分散式事務Laravel分散式
- NOSQL儲存的基於事件的事務實現SQL事件
- sh003基於springboot的汽車租賃系統Spring Boot
- 第三代微服務架構:基於 Go 的部落格微服務實戰案例,支援分散式事務微服務架構Go分散式
- MySQL基於事務的ReplcaitonMySqlAI
- 基於Seata探尋分散式事務的實現方案分散式
- 優效學院 基於微服務的秒殺專案實戰 Spring Boot 2.0基礎微服務Spring Boot
- php基於dtm分散式事務管理器實現tcc模式分散式事務demoPHP分散式模式
- [原創]深入掌握JMS(四):實戰Queue
- [原創]深入掌握JMS(五):實戰Topic
- 分散式事務:基於可靠訊息服務分散式
- 基於 CNN 的驗證碼破解實戰專案CNN
- 分散式事務理論加實戰分散式
- Spring Cloud Seata系列:基於AT模式實現分散式事務SpringCloud模式分散式
- Springboot 實現 Restful 服務,基於 HTTP / JSON 傳輸Spring BootRESTHTTPJSON
- 分散式事務(4)---RocketMQ實現分散式事務專案分散式MQ
- 基於 Spring Cloud 完整的微服務架構實戰SpringCloud微服務架構
- 乾貨!基於SpringBoot的RabbitMQ多種模式佇列實戰Spring BootMQ模式佇列
- 手把手教你使用Go基於zookeeper編寫服務發現「原創」Go
- 事務隔離(二):基於加鎖方式的事務隔離原理
- 構建基於RocketMQ的分散式事務服務MQ分散式
- tcc分散式事務框架原始碼解析系列(四)之專案實戰分散式框架原始碼