OMG_By

沉心、静气、学习、总结、进步


  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

  • 搜索

SpringBoot整合Redis

发表于 2019-07-21 | 分类于 SpringBoot

Spring boot中使用Redis

引入依赖

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

参数配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# REDIS (RedisProperties)
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=localhost
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.pool.max-wait=-1
# 连接池中的最大空闲连接
spring.redis.pool.max-idle=8
# 连接池中的最小空闲连接
spring.redis.pool.min-idle=0
# 连接超时时间(毫秒)
spring.redis.timeout=0

## Redis自定义key配置选项

访问测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(Application.class)
public class ApplicationTests {

@Autowired
private StringRedisTemplate stringRedisTemplate;

@Test
public void test() throws Exception {

// 保存字符串
stringRedisTemplate.opsForValue().set("aaa", "111");
Assert.assertEquals("111", stringRedisTemplate.opsForValue().get("aaa"));

}

}

SpringBoot整合Swagger2

发表于 2019-07-21 | 分类于 SpringBoot , mall

Swagger2

Swagger2用于解决前后端开发人员之间的api对接,减少与其他团队开发期间的沟通成本。Swagger2可以轻松的整合到Spring boot中,并与SpringMVC程序配合组织处强大的Restful API文档。即可以减少我们创建文档的工作量,同时说明内容整合到实现代码中,让维护文档和修改代码整合为一体,可以让我们在修改代码逻辑的同时方便的修改文档说明。
另外,Swagger2也提供了强大的页面测试功能来调试每个Restful API

添加Swagger2依赖

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.2.2</version>
</dependency>
阅读全文 »

Spring boot整合MyBatis逆向工程

发表于 2019-07-18 | 分类于 SpringBoot , mall

pom.xml中添加依赖

在这里引入了pagehelper,pagehelper是MyBatis的分页插件,通过几行简单的代码就是实现分页功能;在与Spring boot整合的时候,只要整合了pagehelper就自动整合了MyBatis。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- spring boot健康检查、审计、统计、监控-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

<!--MyBatis分页插件-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.10</version>
</dependency>
<!-- MyBatis 生成器-->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.3</version>
</dependency>
<!--连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.21</version>
</dependency>
</dependencies>

修改Spring boot配置文件

在application.yml中添加数据源配置和MyBatis的mapper.xml的路径配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
server:
port: 8080

spring:
datasource:
url: jdbc:mysql://127.0.0.1:13307/spring
password: hoo
username: hoo

mybatis:
mapper-locations:
- classpath:mapper/*.xml
- classpath*:com/**/mapper/*.xml

修改Mybatis generator配置文件

主要是修改数据库连接配置,MyBatis generator生成的model、mapper接口、mapper.xml文件的路径。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
<properties resource="generator.properties"/>
<context id="MySqlContext" targetRuntime="MyBatis3" defaultModelType="flat">
<property name="beginningDelimiter" value="`"/>
<property name="endingDelimiter" value="`"/>
<property name="javaFileEncoding" value="UTF-8"/>
<!-- 为模型生成序列化方法-->
<plugin type="org.mybatis.generator.plugins.SerializablePlugin"/>
<!-- 为生成的Java模型创建一个toString方法 -->
<plugin type="org.mybatis.generator.plugins.ToStringPlugin"/>
<!-- 数据库资源配置 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://127.0.0.1:13307/spring"
userId="hoo"
password="hoo">
<!--解决mysql驱动升级到8.0后不生成指定数据库代码的问题-->
<property name="nullCatalogMeansCurrent" value="true" />
</jdbcConnection>
<!-- 生成的model放置路径 -->
<javaModelGenerator targetPackage="com.hoo.springboot.mbg.model" targetProject="./src/main/java"/>
<!-- 生成的mapper接口放置路径 -->
<sqlMapGenerator targetPackage="com.hoo.springboot.mbg.mapper" targetProject="./src/main/resources"/>
<!-- 生成的mapper配置文件放置路径 -->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.hoo.springboot.mbg.mapper"
targetProject="./src/main/java"/>
<!--生成全部表tableName设为%-->
<table tableName="%">
<generatedKey column="id" sqlStatement="MySql" identity="true"/>
</table>
</context>
</generatorConfiguration>

运行Generator的main函数生成代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Generator {
public static void main(String[] args) throws Exception {
//MBG 执行过程中的警告信息
List<String> warnings = new ArrayList<String>();
//当生成的代码重复时,覆盖原代码
boolean overwrite = true;
//读取我们的 MBG 配置文件
InputStream is = Generator.class.getResourceAsStream("/generatorConfig.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(is);
is.close();

DefaultShellCallback callback = new DefaultShellCallback(overwrite);
/* 创建 MBG */
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
//执行生成代码
myBatisGenerator.generate(null);
//输出警告信息
for (String warning : warnings) {
System.out.println(warning);
}
}
}

Java类加载机制

发表于 2019-07-16 | 分类于 Java

类的加载是指将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区,然后在Java堆中创建一个java.lang.Class对象(类也是对象),用来封装类在方法区内的数据结构。
类加载的最终产物是位于堆中的Class对象,该Class对象封装了类在方法区内的数据结构,并且向开发者提供了访问方法区内的数据结构的接口。
ZqjkUs.jpg

类加载器不需要等到某个类被“首次主动使用”时再加载,JVM规范允许类加载器在预料某个类将要被使用的时候就预先加载,如果在预先加载的过程中遇到了.class文件缺失或存在错误,类加载器必须在程序首次主动使用该类时才报告错误,如果这个类一直没有被程序主动使用,那么类加载器就不会报告错误。

类加载过程

ZqjPbQ.jpg

类的生命周期主要包含加载、验证、准备、解析、初始化、使用、卸载。
在加载过程中的五个阶段中,加载、验证、准备、初始化发生的顺序是一定的,而解析在某些情况下可以在初始化阶段之后执行。这是为了支持Java语言的运行时绑定。
另外需要注意的是:这几个阶段是按照顺序开始,而不是按照顺序进行或完成,因为这些阶段通常是相互交叉混合进行的,通常在一个阶段执行的过程中需要调用或激活另一个阶段。

阅读全文 »

Arrays.sort和Collections.sort实现原理

发表于 2019-07-16 | 分类于 Java

事实上,在使用Collections.sort(list)的时候,就调用list.sort()

1
2
3
public static <T extends Comparable<? super T>> void sort(List<T> list) {
list.sort(null);
}

我们在深入进去后,发现其实调用的就是Array.sort()

1
2
3
4
5
6
7
8
9
10
@SuppressWarnings({"unchecked", "rawtypes"})
default void sort(Comparator<? super E> c) {
Object[] a = this.toArray();
Arrays.sort(a, (Comparator) c);
ListIterator<E> i = this.listIterator();
for (Object e : a) {
i.next();
i.set((E) e);
}
}

而在Array.sort中,会根据该对象是否能够通过归并排序来选择不同的排序方式。

1
2
3
4
5
6
7
8
9
10
public static <T> void sort(T[] a, Comparator<? super T> c) {
if (c == null) {
sort(a);
} else {
if (LegacyMergeSort.userRequested)
legacyMergeSort(a, c);
else
TimSort.sort(a, 0, a.length, c, null, 0, 0);
}
}

  • legacyMergeSort:归并排序
  • TimSort
    :结合归并排序和插入排序的一种排序算法

TimSort 算法为了减少对升序部分的回溯和对降序部分的性能倒退,将输入按其升序和降序特点进行了分区。排序的输入的单位不是一个个单独的数字,而是一个个的块-分区。其中每一个分区叫一个run。针对这些 run 序列,每次拿一个 run 出来按规则进行合并。每次合并会将两个 run合并成一个 run。合并的结果保存到栈中。合并直到消耗掉所有的 run,这时将栈上剩余的 run合并到只剩一个 run 为止。这时这个仅剩的 run 便是排好序的结果。

Java线程池解析

发表于 2019-07-15 | 分类于 JAVA

线程池:可以根据字面意思简单的理解,一个管理线程的池子。

  • 帮我们管理线程,避免增加创建线程和销毁线程的资源损耗。
  • 提高响应速度。
  • 重复利用。

构造函数

1
2
3
4
5
6
7
8
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
  • corePoolSize:线程池核心线程数最大值
  • maximumPoolSize: 线程池最大线程数大小
  • keepAliveTime: 线程池中非核心线程空闲的存活时间大小
  • unit: 线程空闲存活时间单位
  • workQueue: 存放任务的阻塞队列
  • threadFactory: 用于设置创建线程的工厂,可以给创建的线程设置有意义的名字,可方便排查问题。
  • handler: 线城池的饱和策略事件,主要有四种类型。

任务执行流程

线程池执行流程,对应execute()方法。
Z7iOzt.md.jpg

阅读全文 »

Bitmap、Bloom Filter、Cuckoo Filter

发表于 2019-07-15 | 分类于 一些奇淫技巧

昨天,在跟同学&同事谈人生谈理想的时候。他告诉我他学长面试头条,其中一道题是如何判断一个整数在不在40亿整数集中;他说他学长竟然不知道bitmap(原题链接)!!!然后我又给他科普了一下布隆过滤器和布谷鸟过滤器。
所以借此文章来记录一下这些知识,并巩固一下。

Bitmap

Bitmap,直译就叫位图。可以理解为通过一个bit数组存储特定数据的一种数据结构;由于bit是数据的最小单位,所以这种数据结构往往是非常节省存储空间的。在Java和Redis中都存在同名实现结构。
在一个记录只有两种状态,是或不是的场景下,如果使用其他数据结构存储则会存在大量空间空间的浪费。即使存在海量的数据,我们也只需要为每个数据分配1byte的空间就可以记录了。比如:用户画像
Bitmap可以节省大量的存储空间,所以可以很容易的倍一次性加载到内存中。Bitmap结构还有一个很重要的特点:可以很方便的进行位运算
比如我们需要统计用户满足以下条件的用户:程序员、带眼镜、长头发。。。。那么我们可以将对相应条件的用户画像的Bitmap结构做AND操作,就可以方便的过滤出满足条件的对象了。

Bitmap的优化

阅读全文 »

mac安装多版本JDK

发表于 2019-07-13 | 分类于 一些奇淫技巧

随着JDK版本的快速迭代,作为优秀(kubi)的Java拥护者,为了跟随时代的潮流,也开始使用1.8版本。

但是,某一天。。。。苦逼的事情发生了,一个项目原本是好好的,突然报错起不来了。最终查到的原因是某个项目的Jar包使用的JDK为1.7….于是就有了这篇记录。

在终端下面使用java -version查看就可以查看使用的JDK版本了。
使用/usr/libexec/java_home -V可以查看本地已经安装的JDK

关于JDK1.x for mac的安装略过,网上有大把的教程。
我这里以安装3个版本1.6/1.7/1.8为例。

一、编辑.bash_profile
vim ~/.bash_profile

二、在.bash_profile中添加下面的内容:

1
2
3
4
5
6
7
8
9
10
11
export JAVA_6_HOME=`/usr/libexec/java_home -v 1.6`
export JAVA_7_HOME=`/usr/libexec/java_home -v 1.7`
export JAVA_8_HOME=`/usr/libexec/java_home -v 1.8`

#默认设为JDK1.7
export JAVA_HOME=$JAVA_7_HOME

#alias命令动态切换JDK版本
alias jdk6="export JAVA_HOME=$JAVA_6_HOME"
alias jdk7="export JAVA_HOME=$JAVA_7_HOME"
alias jdk8="export JAVA_HOME=$JAVA_8_HOME"

三、刷新环境
source ~/.bash_profile

四、测试
执行:jdk8,再执行java -version,看看是不是1.8版本?
执行:jdk6,再执行java -version,看看是不是1.6版本?

Cloneable接口实现原理

发表于 2019-06-04 | 分类于 Java

Cloneable接口是Java开发中常用的一个接口,它的作用是使一个类的实例能够将自身拷贝到另一个新的实例当中。

在开发过程中,如果一个类中的字段比较多,而我们如果采用在客户端中逐字段复制的方法来进行拷贝操作的话,将不可避免的造成客户端代码繁杂,而且也无法对类中的私有对象进行复制,而如果让需要具备拷贝功能的类实现Cloneable接口,并重写clone()方法的方式来简洁地实现实例拷贝功能。

代码分析

private class Demo implements Cloneable{}
我们创建一个Demo类,并让他实现Cloneable接口。

1
2
public interface Cloneable {
}

然后我们发现Cloneable几口里面并没有定义任何接口方法。
这是因为在Object类中已经将clone()方法定义为所有类都应该具有的基本功能,只是将该方法声明为了protected类型。它是一个native本地方法。

如果一个类不实现该接口就直接调用clone()方法的话,就会抛出“不支持拷贝”异常。
所以如果要让一个类具有拷贝实例的功能,那么除了要重写Object类中clone()方法外,还必须实现Cloneable接口。

单例模式

发表于 2019-06-03 | 分类于 编程思想

定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

单例模式多种写法

饿汉模式

这种方式在类加载时就完成了初始化,所以类加载比较慢,但是获取对象的速度快。这种方式基于类加载机制避免了多线程的同步问题。

1
2
3
4
5
6
7
8
public class Singleton {
private static Singleton singleton = new Singleton();
private Singleton(){}

public static Singleton getSingleton() {
return singleton;
}
}

懒汉模式(线程不安全)

懒汉模式声明了一个静态对象,在用户第一次调用时进行初始化,虽然节约了资源,但第一次加载时需要实例化,反应稍微慢一点,而且在多线程下不能工作。

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Singleton{
private static Singleton singleton;

public Singleton() {
}

public static Singleton getSingleton() {
if(singleton == null){
singleton = new Singleton();
}
return singleton;
}
}

阅读全文 »
1…456…14
OMG_By

OMG_By

133 日志
20 分类
36 标签
RSS
GitHub E-Mail
友链
  • 戎码人生
  • JosemyQAQ
  • Just do it !
  • ACM各大OJ题集
  • django大神博客
© 2020 OMG_By