Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
酥脆的小菠萝
hexbook
提交
1714fbbd
H
hexbook
项目概览
酥脆的小菠萝
/
hexbook
通知
5
Star
4
Fork
1
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
H
hexbook
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
1714fbbd
编写于
4月 26, 2021
作者:
S
star
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
代码整洁之道
上级
8b2c4afe
变更
3
展开全部
隐藏空白更改
内联
并排
Showing
3 changed file
with
392 addition
and
2 deletion
+392
-2
notes/Java语言/开源框架/SpringBoot核心基础.md
notes/Java语言/开源框架/SpringBoot核心基础.md
+150
-2
notes/其他/密码学.md
notes/其他/密码学.md
+0
-0
notes/编码实践/代码整洁之道.md
notes/编码实践/代码整洁之道.md
+242
-0
未找到文件。
notes/Java语言/开源框架/SpringBoot核心基础.md
浏览文件 @
1714fbbd
...
...
@@ -220,6 +220,32 @@ Spring,SpringBoot 与 SpringCloud:
SpringBoot 自定义 Starter:
需要用到的注解:
1.
@Configuration:指定配置类
2.
@ConditionalOnXxx:在指定条件成立的情况下自动配置类生效
3.
@AutoConfigureAfter:指定自动配置类的顺序
4.
@Bean:给容器中添加组件
5.
@ConfigurationPropertie:结合相关 xxxProperties 类来绑定相关的配置
6.
@EnableConfigurationProperties:让 xxxProperties 生效加入到容器中
此外,还要将需要启动就加载的自动配置类,配置在 META‐INF/spring.factories 中。
启动器设计规约:
1.
通常来说,SpringBoot Starter 启动器应该只用来做依赖导入,它是一空的 jar 包,用来提供辅助性依赖管理,不应该存在任何的 java 代码。
2.
命名:
1.
官方启动器:spring-boot-starter-xxx,如:spring-boot-starter-web
2.
自定义启动器:xxx-spring-boot-starter,如:druid-spring-boot-starter
---
### 4.SpringBoot AutoConfiguration
...
...
@@ -1610,19 +1636,141 @@ public FilterRegistrationBean<StatViewFilter> statViewFilter(){
*
*结合 MyBatis 配置多数据源**
1
. 搭建项目:创建 SpringBoot 项目,引入需要的项目依赖(不同数据库时需要引入不同的数据库 Driver)。
2
. 编写项目配置:
~~~properties
# 服务端口
server.port=8080
#
MySQL 数据源连接相关信息
spring.datasource.mysql.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.mysql.url=jdbc:mysql://192.168.253.128:3306/common?serverTimezone=UTC
spring.datasource.mysql.username=root
spring.datasource.mysql.password=TinyStar0920
# Oracle 数据源连接相关信息
spring.datasource.oracle.driver-class-name=oracle.jdbc.OracleDriver
spring.datasource.oracle.url=jdbc:oracle:thin:@192.168.253.128:1521:ORCLCDB
spring.datasource.oracle.username=C##STAR
spring.datasource.oracle.password=123456
# Druid 相关配置
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.druid.initial-size=5
# 配置 Druid 监控
spring.datasource.druid.filter.commons-log.connection-logger-name=stat,wall,log4j
spring.datasource.druid.stat-view-servlet.enabled=true
# 日志相关配置
logging.level.com.star.md=debug
~~~
3
. 添加作用在 mapper 上的注解用来使用不同的数据源:
~~~java
@Documented
@Repository
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MysqlRepository {
@AliasFor(annotation = Repository.class)
String value() default "";
}
~~~
同理,添加 OracleRepository 注解。
4
. 使用 MysqlProperties 封装 Mysql 配置属性:
~~~java
@Data
@Component
@ConfigurationProperties(prefix = "spring.datasource.mysql")
public class MysqlProperties {
private String url;
private String username;
private String password;
private String driverClassName;
}
~~~
同理,使用 OracleProperties 封装 Oracle 配置属性。
5
. 配置 DataSource,SessionFactory,SessionTemplate 组件:
~~~java
@Data
@Configuration
@MapperScan(basePackages = "com.star.md.dao", annotationClass = MysqlRepository.class,
sqlSessionFactoryRef = "mysqlSessionFactory", sqlSessionTemplateRef = "mysqlSessionTemplate")
@MapperScan(basePackages = "com.star.md.dao", annotationClass = OracleRepository.class,
sqlSessionFactoryRef = "oracleSessionFactory", sqlSessionTemplateRef = "oracleSessionTemplate")
public class DataSourceConfig {
@Bean
@Primary
public DataSource mysqlDataSource(MysqlProperties properties) {
DruidDataSource mysqlDataSource = DruidDataSourceBuilder.create().build();
mysqlDataSource.setDriverClassName(properties.getDriverClassName());
mysqlDataSource.setUrl(properties.getUrl());
mysqlDataSource.setUsername(properties.getUsername());
mysqlDataSource.setPassword(properties.getPassword());
return mysqlDataSource;
}
@Bean
public SqlSessionFactory mysqlSessionFactory(@Qualifier("mysqlDataSource") DataSource dataSource) throws Exception {
final SqlSessionFactoryBean mysqlSessionFactoryBean = new SqlSessionFactoryBean();
//配置数据源
mysqlSessionFactoryBean.setDataSource(dataSource);
//配置 mysql mapper 文件位置
mysqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("classpath:/mapper/mysql/*Mapper.xml"));
SqlSessionFactory sessionFactory = mysqlSessionFactoryBean.getObject();
assert sessionFactory != null;
sessionFactory.getConfiguration().setMapUnderscoreToCamelCase(true);
return sessionFactory;
}
@Bean
public SqlSessionTemplate mysqlSessionTemplate(@Qualifier("mysqlSessionFactory") SqlSessionFactory sessionFactory) {
return new SqlSessionTemplate(sessionFactory);
}
@Bean
public DataSource oracleDataSource(OracleProperties properties) {
DruidDataSource oracleDataSource = DruidDataSourceBuilder.create().build();
oracleDataSource.setDriverClassName(properties.getDriverClassName());
oracleDataSource.setUrl(properties.getUrl());
oracleDataSource.setUsername(properties.getUsername());
oracleDataSource.setPassword(properties.getPassword());
return oracleDataSource;
}
@Bean
public SqlSessionFactory oracleSessionFactory(@Qualifier("oracleDataSource") DataSource dataSource) throws Exception {
final SqlSessionFactoryBean oracleSessionFactoryBean = new SqlSessionFactoryBean();
//配置数据源
oracleSessionFactoryBean.setDataSource(dataSource);
//配置 oracle mapper 位置
oracleSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("classpath:/mapper/oracle/*Mapper.xml"));
SqlSessionFactory sessionFactory = oracleSessionFactoryBean.getObject();
assert sessionFactory != null;
org.apache.ibatis.session.Configuration sessionConfiguration = sessionFactory.getConfiguration();
sessionConfiguration.setMapUnderscoreToCamelCase(true);
return sessionFactory;
}
@Bean
public SqlSessionTemplate oracleSessionTemplate(@Qualifier("oracleSessionFactory") SqlSessionFactory sessionFactory) {
return new SqlSessionTemplate(sessionFactory);
}
}
~~~
1. 向容器中添加了 2 个数据源, 2 个 SqlSessionFactory,2 个 SqlSessionTemplate。
2. 使用 **@MapperScan** 标注了要扫描的 mapper 组件,由于容器中存在多个 SqlSessionFactory 和多个 SqlSessionTemplate 组件,所以还要额外为扫描到的 mapper 指定要使用的 SqlSessionFactory 和 SqlSessionTemplate。
...
...
notes/其他/密码学.md
0 → 100644
浏览文件 @
1714fbbd
此差异已折叠。
点击以展开。
notes/编码实践/代码整洁之道.md
0 → 100644
浏览文件 @
1714fbbd
:bulb:
***Later equals never.**
*
#### 1.有意义的命名
软件中随处可见命名,我们给变量、函数、类和包命名,下面是起一个好名字应该遵从的规则。
==名副其实==
选个好名字要花时间,但是省下来的时间比花掉的多,注意命名,而且一旦发现有更好的命名就换掉旧的,这样做,读代码的人都会更开心。
1.
指明计量单位和计量单位的名称,如:int elapsedTimeInDays、int fileAgeInDays 等。
2.
选择体现业务本意的名称,而不是字母(如:d、e),类型(如:theList、list1)等名称。
3.
利用类代替复杂的数据结构。
例如:应用中使用 int
\[
]
\[
] 数组表示坐标,如果在代码中大量使用这个二维数组,代码会变得极其繁杂,我们可以定义一个类
~~~
java
public
class
Position
{
private
int
value
;
private
int
x
;
private
int
y
;
}
~~~
4.
避免使用魔术变量(未经定义的常量),例如:
~~~
java
if
(
age
==
5
){
// do something
}
~~~
此时,我们应当将 5 这个魔术数放到文件前面并定义一个数字,如:
`private static final int MIN_AGE = 5;`
。
==避免误导==
程序员必须避免留下掩藏代码本意的错误线索,避免使用与本意相悖的词。
1.
避免使用某些专有名称作为变量名,例如:aix、sco、bat 等,虽然看起来像是不错的缩写,但是极易引起误导。
2.
不要使用 accountList 来表示一组账号,除非它真的是 List 类型,否则会引起错误的判断,此时使用 accountGroup 或 accounts 都是更好的选择。
3.
不要使用外形相似度较高的名称,例如 XYZControllerForEfficientHandlingOfStrings 和 XYZControllerForEfficientStorageOfStrings,更有甚者使用小写的字母 l 和大写的字母 O,他们看起来完全像常量「壹」和「零」。
==做有意义的区分==
在代码中,同一作用范围的两样不同的东西不能重名,如果我们只是为满足编译器或解释器的需要而修改代码,那么将会带来无尽麻烦。
1.
只是在命名后添加数字远远不够,每个不同的命名都应该能表达出不同的意义,如 a1、a2、a3、a4... 等名称纯属误导,完全没有提供正确的信息,例:
~~~
java
public
void
copyChars
(
char
[]
c1
,
char
[]
c2
)
{
for
(
i
=
0
;
i
<
c1
.
length
;
i
++)
{
c2
[
i
]
=
c1
[
i
];
}
}
~~~
此时,两个参数名 c1 和 c2 完全没有任何意义,如果将其替换为 source 和 destination,函数就会好看许多。
2.
避免使用废话来区分命名,假设有一个 Product 类,还有一个 ProductData 和 ProductInfo 类,那么它们虽然名称不同,但是都是意义含混的废话;当我们面对 getActiveAccount、getActiveAccounts 和 getActiveAccountInfo 这 3 个函数时,也无法快速的分辨到底该调用哪一个函数。
3.
避免冗余的命名,例如 variable 永远不要出现在变量名中,table 永远不要出现在数据库表名中,nameString 也不会比 name 更好。
==使用读得出来的名称==
人类擅长于记忆和使用单词,如果名称读不出来,在讨论的时候就会变得十分尴尬。
1.
不要使用字母组合命名,例如程序里面有一个 genymdhms 函数(生成年月日时分秒),这样的函数名完全无法读出来也无法一眼看出它的含义,如果换成 genTimestamp 这样的命名就会使函数读起来更像人话。
2.
不要使用不恰当的缩写,例如:DtaRcrd、Cstm、Acct 并不会比 DataRecord、Customer、Account 这些完整的单词更好更简洁。
==使用可搜索的名称==
对于单字母名称和数字常量,有一个问题就是很难再一大段代码中搜索出来。
1.
搜索 MAX_CLASSES_PER_STUDENT 很容易,但是查找数字 7 就比较麻烦了,同时字母 e、s 等也不是一个便于搜索的好名称,我们应该尽量避免使用单字母名称和数字常量。
2.
名称长短应该与其作用域大小相对应,如果变量或常量可能在代码中多处使用,则应该赋予它们便于搜索的名称。
==避免使用标记==
现代编程语言有丰富的类型系统,并且强制使用类型,所以把类型和作用域编进名称里面,只会突然增加负担。
1.
不必使用 m_ 来标记成员变量,我们要学会无视前缀或后缀,只看到名称中有意义的部分。
2.
在创建接口时,不要使用前导字母 I,比如 IShapeFactory 对于 ShapeFactory 来说,前面的 I 字母根本就是一句废话。
==类名和方法名==
1.
类名和对象名应该是名称和名词短语,例如 Customer、Account 等,此外还要避免使用 Data、Info、Manager 这样语义广泛的名称。
2.
方法名应当是动词或动词短语,如 postPayment、deletePage 等。
==一词一义==
1.
每个概念值对应一个词,假如一堆代码中的控制器有 controller、manager 和 driver,name就会让人产生困惑,我们的命名应当一以贯之。
2.
避免将同一单词用于不同目的(双关),例如:使用 add 用于向集合中添加元素,而在另外的地方用来拼接字符串,这种做法是强烈禁止的。
==使用解决方案领域名称和问题领域名称==
1.
只有程序员才会读你的代码,所以我们可以尽情的使用那些计算机科学术语,算法名,模式名,没有程序员不知道 AccoutVisitor 的含义,同样,大多数程序员也都了解 JobQueue 的含义。
2.
如果不能使用程序员熟悉的术语进行命名,那么可以考虑从所涉及的问题的领域获取命名,与软件的实际功能更为贴近。
==为代码添加语境==
很少有名称是能够自我说明的,如果不能自我说明,我们还剩最后一招,给名称添加前缀语境。
1.
当我们看见一堆单词如 state、city、street、name、houseNumber 时,我们很容易推断这是一个地址的描述,但是如果我们只看见一个孤零零的 name 变量呢,我们无法进行推断,但是我们可以添加前缀进行说明:addrName,这样我们就可以明白这个变量是更大结构的一部分。
2.
当需要使用到一堆相关联的变量时,可以使用一个类封装它们,类也是语境的一部分。
3.
不要添加无意义的语境,假如有一个名为 Gas Station Deluxe(加油站豪华版)的应用,如果给其中的每一个类都加上 GSD 前缀就不是什么好点子了;只要名称足够清楚,短名称就比长名称好。
---
#### 2.函数
在编程的早期岁月,系统由程序和子程序组成,后来到了 Fortran 和 PL/1 的年代,系统由程序、子程序和函数组成,如今只有函数保留了下来,函数是所有程序中的第一组代码。
==短小==
函数的第一条规则是短小,第二条规则还是要短小。
1. 函数尽量不要写得过长,**20** 行封顶最佳。
> :gear: 个人不倾向于这这么短的函数,频繁的函数调用不仅不会降低代码编写难度,还会提高难度。一般情况下,**50-60** 行左右封顶为最佳。
2. if、else、while 等语句,其中的代码应该只占一行,该行一般为一个函数调用语句,这样能够很好的保持函数大小。
3. 函数中的代码嵌套层级(if、while 等嵌套)不宜过多,否则不易于阅读和理解,最好是一层或两层,不可超过三层。
==只做一件事==
函数应该只做一件事,做好这件事,只做一件事。
如何判断函数只做了一件事,还是做了几件事?例:
~~~java
public void buy() {
// 1.走进商店
// 2.选好商品
// 3.掏出钱包
// 4.付钱
// 5.放回钱包
// 6.走出商店
}
~~~
在这个函数中,模拟了一个买东西的情节,其中 1、2、6 步骤都是买东西过程下的抽象层中的一件事,但是 3、4、5 却是在买东西这个动作下的更细分的步骤,很明显不属于函数名下的抽象层,此时 3、4、5 就合一被拆出一个新函数「结账」。
>
:yellow_heart:
向下原则:让每个函数后面跟着位于下一抽象层及的函数,在阅读时就能遵循抽象层级向下阅读。
=
=使用具有描述性的名称==
为
函数起一个具有描述性的名称,函数的功能越集中,就越便于起一个好名字。
不
要害怕长名称,长名称要比短而费解的短名称好。
在
同一个模块中,函数的命名方式要保持一致,使用与模块名一脉相承的短语、名词和动词给函数命名。
=
=函数参数==
最
理想的函数参数是 0,其次是 1,再次是 2,应当尽量避免 3 参数的函数(除非万不得已)。
1
. 一般来说,信息通过参数输入函数,然后通过返回值进行输出,所以尽量不要在参数中输出函数结果。
2
. 不要使用标识参数:向函数输入 boolean 值是一种不优雅的做法,相当于大声宣布本函数不只做一件事,在任何情况下我们都不要这样做;此时我们应该将这种情况拆分为 2 个函数 doXxxForXxx 和 doXxxForNonXxx。
3
. 双参数函数:
1. 两个参数最好是某个值的有序组成部分,如:`new Point(0, 0);`。
2. 使用两个同类型的参数时,应额外注意其先后顺序,如:`assertEquals(expected, actual);`中一般约定期望值在前,实际值在后。
3. 尽量的转化双参数函数为单参数函数,可以使用诸如添加成员变量、新建一个类等方法。
4
. 三参数函数:如果一个函数看起来需要 2 个、3 个及 3 个以上的参数,说明一些参数应该封装成类了,例:
~~~java
Circle makeCircle(double x, double y, double radius);
Circle makeCircle(Point center, double radius);
~~~
5
. 可变参数:在 Java 中,可以使用 ... 向函数传入可变长度的参数。
6
. 函数和参数应当形成一种非常良好的动词/名词的对应关系,例如: `writeField(name);`。
=
=分割指令和询问==
1
. 函数要么做什么事,要么回答什么事,两者不可得兼,例:
~~~java
boolean isSuccess = setAttribute("username", "unclebob");
---------------------------------------------------------
if(attributeExists("username")) {
setAttribute("username", "unclebob");
}
~~~
此两种代码明显后者更优。
2
. 使用异常替代返回错误码,将询问以异常的形式抛出,能够很好的分割指令和询问。
1. 将 try/catch 代码块单独抽离乘一个函数,使之从主代码块中分离出来,代码就会变得更简洁。
2. 错误处理就是一件事,处理错误的函数不应该做其他的事,如果在抛出错误的时候需要做另外的一件事,那么应该好好考虑此处是否应该抛出错误。
3. 尽量使用异常代替错误码,返回错误码一般是一个枚举类,其他许多类都要依赖并使用它,使得在修改这个枚举类时造成了很大的负面压力,所以,尽量使用异常派生类。
-
--
#### 3.注释
\ No newline at end of file
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录