springboot cache小记

寻寻觅觅找教程,无疑是一个吃力不讨好的差事,有写的不好的,也有写的好的,但终究有一点那就是不系统。而对于一门技术权威介绍的书籍,又不知道等几年之后才能出版,看着密密麻麻的英文官方文档,特么的一口又一口的老血就喷到了屏幕上。再喷,也得学啊。学啊学啊,又陷入到上面的循环之中。老话说的好,要想知道河的深浅,就得亲自下河摸鱼。SO,本文很纯粹的介绍了主题cache的一小部分,理论不多,重在通过项目给大家和我自己一个入门级别的引导,方便日后查看。

为了不浪费大家找答案的时间,突然有所感慨,记录在上面。重点看最后一句。

代码验证环境:idea。

场景

我们经常需要通过id来查询实体,正常不用的缓存的情况是:请求URL,查询数据库,返回结果。使用缓存的情况:请求URL-查询缓存-缓存中有直接返回,缓存中无查询数据库-返回结果。

验证步骤

1.使用idea 新建springboot项目pom文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example.testcache</groupId>
    <artifactId>democache</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>democache</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</project>

2.我们要模拟查询数据的过程需要DAO 层,service层提供服务。涉及的几个类如下:
实体类book:

public class Book {
    private String isbn;
    private String title;

    public Book(String isbn, String title) {
        this.isbn = isbn;
        this.title = title;
    }

    public String getIsbn() {
        return isbn;
    }

    public void setIsbn(String isbn) {
        this.isbn = isbn;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    @Override
    public String toString() {
        return "Book{" +
                "isbn='" + isbn + '\'' +
                ", title='" + title + '\'' +
                '}';
    }
}

查询接口BookRepository:

public interface BookRepository {
    Book getByIsbn(String isbn);
}

接口实现SimpleBookRepository:

@Component
public class SimpleBookRepository implements BookRepository {

    @Override
    public Book getByIsbn(String isbn) {

        simulateSlowService();
        return new Book(isbn, "Some book");

    }

    private void simulateSlowService() {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            throw new IllegalStateException(e);
        }
    }
}

以上代码在查询的时候加入了3秒的延迟,你可以随时修改它。
准备工作做好之后我们分别验证一下两种情况。

无缓存的情况

众所周知运行springboot的方式很简单,启动类:

@SpringBootApplication
public class DemocacheApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemocacheApplication.class, args);
    }
}

@SpringBootApplication注解巴拉巴拉。就不解释了。

没有建测试类,我们通过实现CommandLineRunner接口的方式注入bookRepository,去掉用查询方法。

@Component
public class AppRunner implements CommandLineRunner {


    private static final Logger logger = LoggerFactory.getLogger(AppRunner.class);


    private final BookRepository bookRepository;

    public AppRunner(BookRepository bookRepository) {
        this.bookRepository = bookRepository;
    }

    @Override
    public void run(String... strings) throws Exception {
        logger.info(".... Fetching books");
        logger.info("isbn-1234 -->" + bookRepository.getByIsbn("isbn-1234"));
        logger.info("isbn-4567 -->" + bookRepository.getByIsbn("isbn-4567"));
        logger.info("isbn-1234 -->" + bookRepository.getByIsbn("isbn-1234"));
        logger.info("isbn-4567 -->" + bookRepository.getByIsbn("isbn-4567"));
        logger.info("isbn-1234 -->" + bookRepository.getByIsbn("isbn-1234"));
        logger.info("isbn-1234 -->" + bookRepository.getByIsbn("isbn-1234"));

    }
}

输入如下:

2017-05-27 10:58:55.800 INFO 8233 — [ main] com.example.testcache.AppRunner : …. Fetching books
2017-05-27 10:58:58.806 INFO 8233 — [ main] com.example.testcache.AppRunner : isbn-1234 –>Book{isbn=’isbn-1234’, title=’Some book’}
2017-05-27 10:59:01.809 INFO 8233 — [ main] com.example.testcache.AppRunner : isbn-4567 –>Book{isbn=’isbn-4567’, title=’Some book’}
2017-05-27 10:59:04.812 INFO 8233 — [ main] com.example.testcache.AppRunner : isbn-1234 –>Book{isbn=’isbn-1234’, title=’Some book’}
2017-05-27 10:59:07.813 INFO 8233 — [ main] com.example.testcache.AppRunner : isbn-4567 –>Book{isbn=’isbn-4567’, title=’Some book’}

从输出的日志来看,大概每3秒检索一次。

启用缓存

修改SimpleBookRepository.java类的检索方法:

@Component
public class SimpleBookRepository implements BookRepository {

    @Override
    @Cacheable("books")
    public Book getByIsbn(String isbn) {

        simulateSlowService();
        return new Book(isbn, "Some book");

    }

    private void simulateSlowService() {
        try {
            Thread.sleep(3000L);
        } catch (InterruptedException e) {
            throw new IllegalStateException(e);
        }
    }
}

除此之外,还需要在启动类上加上@EnableCaching注解:

@SpringBootApplication
@EnableCaching
public class DemocacheApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemocacheApplication.class, args);
    }
}

@EnableCaching小讲

@EnableCaching注解会检查spring bean的公共方法上是否存在缓存注解,如果找到这样的注释,则会自动创建代理来拦截方法调用并相应地处理缓存行为。
能被它监测到的注解有我们很熟的 Cacheable, CachePut 和 CacheEvict等。
Spring Boot自动配置一个合适的缓存管理器,我们的例子没有使用指定的缓存库例如EHcache,所以我们使用的是spring自己的基于java.util.concurrent.ConcurrentHashMap实现的缓存管理器(该功能是从Spring3.1开始提供)。

再次启动应用我们看到结果:

2017-05-27 11:28:21.843 INFO 8318 — [ main] com.example.testcache.AppRunner : …. Fetching books
2017-05-27 11:28:24.855 INFO 8318 — [ main] com.example.testcache.AppRunner : isbn-1234 –>Book{isbn=’isbn-1234’, title=’Some book’}
2017-05-27 11:28:27.860 INFO 8318 — [ main] com.example.testcache.AppRunner : isbn-4567 –>Book{isbn=’isbn-4567’, title=’Some book’}
2017-05-27 11:28:27.861 INFO 8318 — [ main] com.example.testcache.AppRunner : isbn-1234 –>Book{isbn=’isbn-1234’, title=’Some book’}
2017-05-27 11:28:27.861 INFO 8318 — [ main] com.example.testcache.AppRunner : isbn-4567 –>Book{isbn=’isbn-4567’, title=’Some book’}
2017-05-27 11:28:27.862 INFO 8318 — [ main] com.example.testcache.AppRunner : isbn-1234 –>Book{isbn=’isbn-1234’, title=’Some book’}
2017-05-27 11:28:27.862 INFO 8318 — [ main] com.example.testcache.AppRunner : isbn-1234 –>Book{isbn=’isbn-1234’, title=’Some book’}

会发现,只要请求已访问过的实体,会立即从缓存中返回结果。

发布了22 篇原创文章 · 获赞 9 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_19408473/article/details/72779919
今日推荐