最后希望可以帮助到大家!
千千万万要记得:多刷题!!多刷题!!
之前算法是我的硬伤,后面硬啃了好长一段时间才补回来,算法才是程序员的灵魂!!!!
篇幅有限,以下只能截图分享部分的资源!!
(1)多线程(这里以多线程为代表,其实整理了一本JAVA核心架构笔记集)
(2)刷的算法题(还有左神的算法笔记)
(3)面经+真题解析+对应的相关笔记(很全面)
(4)视频学习(部分)
ps:当你觉得学不进或者累了的时候,视频是个不错的选择
在这里,最后只一句话:祝大家offer拿到手软!!
该项目需要引入如下依赖:springBoot、spring-aop、spring-jdbc、aspectjweaver等。
一、主从数据源的配置
我们需要配置主从数据库,主从数据库的配置一般都是写在配置文件里面。通过@ConfigurationProperties注解,可以将配置文件(一般命名为:application.Properties)里的属性映射到具体的类属性上,从而读取到写入的值注入到具体的代码配置中,按照习惯大于约定的原则,主库我们都是注为master,从库注为slave,本项目采用了阿里的druid数据库连接池,使用build建造者模式创建DataSource对象,DataSource就是代码层面抽象出来的数据源,接着需要配置sessionFactory、sqlTemplate、事务管理器等。
/**
-
主从配置
-
@author wyq
-
@date 2020年07月24日01:24:42
*/
@Configuration
@MapperScan(basePackages = “com.wyq.mysqlreadwriteseparate.mapper”, sqlSessionTemplateRef = “sqlTemplate”)
public class DataSourceConfig {
/**
- 主库
*/
@Bean
@ConfigurationProperties(prefix = “spring.datasource.master”)
public DataSource master() {
return DruidDataSourceBuilder.create().build();
}
/**
- 从库
*/
@Bean
@ConfigurationProperties(prefix = “spring.datasource.slave”)
public DataSource slaver() {
return DruidDataSourceBuilder.create().build();
}
/**
- 实例化数据源路由
*/
@Bean
public DataSourceRouter dynamicDB(@Qualifier(“master”) DataSource masterDataSource,
@Autowired(required = false) @Qualifier(“slaver”) DataSource slaveDataSource) {
DataSourceRouter dynamicDataSource = new DataSourceRouter();
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put(DataSourceEnum.MASTER.getDataSourceName(), masterDataSource);
if (slaveDataSource != null) {
targetDataSources.put(DataSourceEnum.SLAVE.getDataSourceName(), slaveDataSource);
}
dynamicDataSource.setTargetDataSources(targetDataSources);
dynamicDataSource.setDefaultTargetDataSource(masterDataSource);
return dynamicDataSource;
}
/**
-
配置sessionFactory
-
@param dynamicDataSource
-
@return
-
@throws Exception
*/
@Bean
public SqlSessionFactory sessionFactory(@Qualifier(“dynamicDB”) DataSource dynamicDataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setMapperLocations(
new PathMatchingResourcePatternResolver().getResources(“classpath*:mapper/*Mapper.xml”));
bean.setDataSource(dynamicDataSource);
return bean.getObject();
}
/**
-
创建sqlTemplate
-
@param sqlSessionFactory
-
@return
*/
@Bean
public SqlSessionTemplate sqlTemplate(@Qualifier(“sessionFactory”) SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
/**
-
事务配置
-
@param dynamicDataSource
-
@return
*/
@Bean(name = “dataSourceTx”)
public DataSourceTransactionManager dataSourceTransactionManager(@Qualifier(“dynamicDB”) DataSource dynamicDataSource) {
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(dynamicDataSource);
return dataSourceTransactionManager;
}
}
二、数据源路由的配置
路由在主从分离是非常重要的,基本是读写切换的核心。
Spring提供了AbstractRoutingDataSource 根据用户定义的规则选择当前的数据源,作用就是在执行查询之前,设置使用的数据源,实现动态路由的数据源,在每次数据库查询操作前执行它的抽象方法 determineCurrentLookupKey() 决定使用哪个数据源,为了能有一个全局的数据源管理器,此时我们需要引入DataSourceContextHolder这个数据库上下文管理器,可以理解为全局的变量,随时可取(见下面详细介绍),它的主要作用就是保存当前的数据源;
public class DataSourceRouter extends AbstractRoutingDataSource {
/**
-
最终的determineCurrentLookupKey返回的是从DataSourceContextHolder中拿到的,因此在动态切换数据源的时候注解
-
应该给DataSourceContextHolder设值
-
@return
*/
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.get();
}
}
三、数据源上下文环境
数据源上下文保存器,便于程序中可以随时取到当前的数据源,它主要利用ThreadLocal封装,因为ThreadLocal是线程隔离的,天然具有线程安全的优势。这里暴露了set和get、clear方法,set方法用于赋值当前的数据源名,get方法用于获取当前的数据源名称,clear方法用于清除ThreadLocal中的内容,因为ThreadLocal的key是weakReference是有内存泄漏风险的,通过remove方法防止内存泄漏;
/**
- 利用ThreadLocal封装的保存数据源上线的上下文context
*/
public class DataSourceContextHolder {
private static final ThreadLocal context = new ThreadLocal<>();
/**
-
赋值
-
@param datasourceType
*/
public static void set(String datasourceType) {
context.set(datasourceType);
}
/**
-
获取值
-
@return
*/
public static String get() {
return context.get();
}
public static void clear() {
context.remove();
}
}
四、切换注解和Aop配置
首先我们来定义一个@DataSourceSwitcher注解,拥有两个属性①当前的数据源②是否清除当前的数据源,并且只能放在方法上,(不可以放在类上,也没必要放在类上,因为我们在进行数据源切换的时候肯定是方法操作),该注解的主要作用就是进行数据源的切换,在dao层进行操作数据库的时候,可以在方法上注明表示的是当前使用哪个数据源;
@DataSourceSwitcher注解的定义:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface DataSourceSwitcher {
/**
-
默认数据源
-
@return
*/
DataSourceEnum value() default DataSourceEnum.MASTER;
/**
-
清除
-
@return
*/
boolean clear() default true;
}
DataSourceAop配置
为了赋予@DataSourceSwitcher注解能够切换数据源的能力,我们需要使用AOP,然后使用@Aroud注解找到方法上有@DataSourceSwitcher.class的方法,然后取注解上配置的数据源的值,设置到DataSourceContextHolder中,就实现了将当前方法上配置的数据源注入到全局作用域当中;
@Slf4j
@Aspect
言尽于此,完结
无论是一个初级的 coder,高级的程序员,还是顶级的系统架构师,应该都有深刻的领会到设计模式的重要性。
- 第一,设计模式能让专业人之间交流方便,如下:
程序员A:这里我用了XXX设计模式
程序员B:那我大致了解你程序的设计思路了
- 第二,易维护
项目经理:今天客户有这样一个需求…
程序员:明白了,这里我使用了XXX设计模式,所以改起来很快
- 第三,设计模式是编程经验的总结
程序员A:B,你怎么想到要这样去构建你的代码
程序员B:在我学习了XXX设计模式之后,好像自然而然就感觉这样写能避免一些问题
- 第四,学习设计模式并不是必须的
程序员A:B,你这段代码使用的是XXX设计模式对吗?
程序员B:不好意思,我没有学习过设计模式,但是我的经验告诉我是这样写的
从设计思想解读开源框架,一步一步到Spring、Spring5、SpringMVC、MyBatis等源码解读,我都已收集整理全套,篇幅有限,这块只是详细的解说了23种设计模式,整理的文件如下图一览无余!
搜集费时费力,能看到此处的都是真爱!
是这样写的
[外链图片转存中…(img-ISVbox2W-1715720946325)]
从设计思想解读开源框架,一步一步到Spring、Spring5、SpringMVC、MyBatis等源码解读,我都已收集整理全套,篇幅有限,这块只是详细的解说了23种设计模式,整理的文件如下图一览无余!
[外链图片转存中…(img-QTROUsgs-1715720946325)]
搜集费时费力,能看到此处的都是真爱!