In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/01 Report--
This article mainly introduces the relevant knowledge of "how to achieve a read-write separation component in SpringBoot". The editor shows you the operation process through an actual case. The operation method is simple, fast and practical. I hope this article "how to achieve a read-write separation component in SpringBoot" can help you solve the problem.
1.pom.xml configuration file org.springframework.boot spring-boot-starter org.springframework.boot spring-boot-starter-data-jpa org.springframework.boot spring-boot-configuration-processor true 2.application.yml configuration file pack: datasource: pointcut: execution (public * net.greatsoft.service.base. *. * (..) | | execution (public * net.greatsoft.service.xxx.*.* (..)) Master: driverClassName: oracle.jdbc.driver.OracleDriver jdbcUrl: jdbc:oracle:thin:@10.100.102.113:1521/orcl username: test password: test minimumIdle: 10 maximumPoolSize: 200 autoCommit: true idleTimeout: 30000 poolName: MbookHikariCP maxLifetime: 1800000 connectionTimeout: 30000 connectionTestQuery: SELECT 1 FROM DUAL slaves:-driverClassName: oracle.jdbc.driver.OracleDriver JdbcUrl: jdbc:oracle:thin:@10.100.102.113:1521/orcl username: dc password: dc minimumIdle: 10 maximumPoolSize: 200 autoCommit: true idleTimeout: 30000 poolName: MbookHikariCP maxLifetime: 1800000 connectionTimeout: 30000 connectionTestQuery: SELECT 1 FROM DUAL-driverClassName: oracle.jdbc.driver.OracleDriver jdbcUrl: jdbc:oracle:thin : @ 10.100.102.113:1521/orcl username: empi password: empi minimumIdle: 10 maximumPoolSize: 200 autoCommit: true idleTimeout: 30000 poolName: MbookHikariCP maxLifetime: 1800000 connectionTimeout: 30000 connectionTestQuery: SELECT 1 FROM DUAL
Pointcut: define pointcuts, which methods need to be intercepted (operated from the read library).
Master: write the library configuration.
Slaves: read the library configuration (List collection).
3. Property configuration class @ Component @ ConfigurationProperties (prefix = "pack.datasource") public class RWDataSourceProperties {private String pointcut; private HikariConfig master; private List slaves = new ArrayList ();} 4. Read-write configuration class public class RWConfig {private static Logger logger = LoggerFactory.getLogger (RWConfig.class); @ Bean public HikariDataSource masterDataSource (RWDataSourceProperties rwDataSourceProperties) {return new HikariDataSource (rwDataSourceProperties.getMaster ());} @ Bean public List slaveDataSources (RWDataSourceProperties rwDataSourceProperties) {List lists = new ArrayList (); for (HikariConfig config: rwDataSourceProperties.getSlaves ()) {lists.add (new HikariDataSource (config)) } return lists; @ Bean @ Primary @ DependsOn ({"masterDataSource", "slaveDataSources"}) public AbstractRoutingDataSource routingDataSource (@ Qualifier ("masterDataSource") DataSource masterDataSource, @ Qualifier ("slaveDataSources") List slaveDataSources) {BaseRoutingDataSource ds = new BaseRoutingDataSource (); Map targetDataSources = new HashMap (2); targetDataSources.put ("master", masterDataSource); for (int I = 0) I < slaveDataSources.size ()) {targetDataSources.put ("slave-" + I, slaveDataSources.get (I));} ds.setDefaultTargetDataSource (masterDataSource); ds.setTargetDataSources (targetDataSources); return ds;}} 5. Data source routing
Public class BaseRoutingDataSource extends AbstractRoutingDataSource {
@ Resource
Private DataSourceHolder holder
@ Override
Protected Object determineCurrentLookupKey () {
Return holder.get ()
}
}
Public class DataSourceHolder {private ThreadLocal context = new ThreadLocal () {@ Override protected Integer initialValue () {return 0;}}; @ Resource private BaseSlaveLoad slaveLoad; public String get () {Integer type = context.get (); return type = = null | | type = = 0? "master": "slave-" + slaveLoad.load ();} public void set (Integer type) {context.set (type);}}
The content value of context is set dynamically through aop, 0 is operated from the write library, and the rest is operated in the read library.
The BaseSlaveLoad class is an algorithm class selected from that library, and the default implementation uses the polling algorithm.
Public interface BaseSlaveLoad {
Int load ()
}
Public abstract class AbstractSlaveLoad implements BaseSlaveLoad {@ Resource protected List slaveDataSources;}
An abstract class is defined here and the list of read libraries is injected, and all the implementation classes can inherit from this class.
Public class PollingLoad extends AbstractSlaveLoad {private int index = 0; private int size = 1; @ PostConstruct public void init () {size = slaveDataSources.size ();} @ Override public int load () {int n = index; synchronized (this) {index = (+ + index)% size;} return n;}
Configure as Bean
@ Bean @ ConditionalOnMissingBean public BaseSlaveLoad slaveLoad () {return new PollingLoad ();} @ Bean public DataSourceHolder dataSourceHolder () {return new DataSourceHolder ();} 6. Data source AOPpublic class DataSourceAspect implements MethodInterceptor {private DataSourceHolder holder; public DataSourceAspect (DataSourceHolder holder) {this.holder = holder;} @ Override public Object invoke (MethodInvocation invocation) throws Throwable {Method method = invocation.getMethod (); String methodName = method.getName (); SlaveDB slaveDB = method.getAnnotation (SlaveDB.class) If (slaveDB = = null) {slaveDB = method.getDeclaringClass () .getAnnotation (SlaveDB.class) } if (methodName.startsWith ("find") | | methodName.startsWith ("get") | | methodName.startsWith ("query") | | methodName.startsWith ("select") | | methodName.startsWith ("list") | | slaveDB! = null) {holder.set (1) } else {holder.set (0);} return invocation.proceed ();}}
The pointcut needs to be configured dynamically, so here we use spring aop to configure it.
@ Bean public AspectJExpressionPointcutAdvisor logAdvisor (RWDataSourceProperties props, DataSourceHolder holder) {AspectJExpressionPointcutAdvisor advisor = new AspectJExpressionPointcutAdvisor (); logger.info ("execute expression: {}", props.getPointcut ()); advisor.set_Expression (props.getPointcut ()); advisor.setAdvice (new DataSourceAspect (holder)); return advisor } 7.Enable enable function public class RWImportSelector implements ImportSelector {@ Override public String [] selectImports (AnnotationMetadata importingClassMetadata) {return new String [] {RWConfig.class.getName ()};}}
The RWConfig here is the configuration class above
@ Retention (RetentionPolicy.RUNTIME)
@ Target (ElementType.TYPE)
@ Documented
@ Import ({RWImportSelector.class})
Public @ interface EnableRW {
}
Documented @ Retention (RUNTIME) @ Target ({TYPE, METHOD}) public @ interface SlaveDB {}
Annotated methods with @ SlaveDB will operate from the reader library.
At this point, the read-write separation component development is complete.
8. Package and install to the local warehouse mvn install-Dmaven.test.skip=true9. Create a new base-web project
Introduce dependency
Com.pack xg-component-rw 1.0.0
Start the class to add comments to enable the read-write separation function
@ SpringBootApplication @ EnableRW public class BaseWebApplication {public static void main (String [] args) {SpringApplication.run (BaseWebApplication.class, args);}}
Test:
First query:
Second query:
In order to distinguish between two sets of different data from the library
This is the end of the introduction to "how to implement a read-write separation component in SpringBoot". Thank you for your reading. If you want to know more about the industry, you can follow the industry information channel. The editor will update different knowledge points for you every day.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.