|
| 1 | +## Spring Boot简介 |
| 2 | +Spring Boot是为了简化Spring开发而生,从Spring 3.x开始,Spring社区的发展方向就是弱化xml配置文件而加大注解的戏份。最近召开的SpringOne2GX2015大会上显示:Spring Boot已经是Spring社区中增长最迅速的框架,前三名是:Spring Framework,Spring Boot和Spring Security,这个应该是未来的趋势。 |
| 3 | + |
| 4 | +我学习Spring Boot,是因为通过cli工具,spring boot开始往flask(python)、express(nodejs)等web框架发展和靠近,并且Spring Boot几乎不需要写xml配置文件。感兴趣的同学可以根据[spring boot quick start](http://projects.spring.io/spring-boot/#quick-start)这篇文章中的例子尝试下。 |
| 5 | + |
| 6 | +学习新的技术最佳途径是看官方文档,现在Spring boot的release版本是1.3.0-RELEASE,相应的参考文档是[Spring Boot Reference Guide(1.3.0-REALEASE)](http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/),如果有绝对英文比较吃力的同学,可以参考中文版[Spring Boot参考指南](https://www.gitbook.com/book/qbgbook/spring-boot-reference-guide-zh/details)。在前段时间阅读一篇技术文章,介绍如何阅读ios技术文档,我从中也有所收获,那就是我们应该重视spring.io上的guides部分——[Getting Started Guides](http://spring.io/guides),这部分都是一些针对特定问题的demo,值得学习。 |
| 7 | + |
| 8 | +## Spring Boot的项目结构 |
| 9 | +``` |
| 10 | +com |
| 11 | + +- example |
| 12 | + +- myproject |
| 13 | + +- Application.java |
| 14 | + | |
| 15 | + +- domain |
| 16 | + | +- Customer.java |
| 17 | + | +- CustomerRepository.java |
| 18 | + | |
| 19 | + +- service |
| 20 | + | +- CustomerService.java |
| 21 | + | |
| 22 | + +- web |
| 23 | + +- CustomerController.java |
| 24 | +``` |
| 25 | +如上所示,Spring boot项目的结构划分为web->service->domain,其中domain文件夹可类比与业务模型和数据存储,即xxxBean和Dao层;service层是业务逻辑层,web是控制器。比较特别的是,这种类型的项目有自己的入口,即主类,一般命名为Application.java。Application.java不仅提供入口功能,还提供一些底层服务,例如缓存、项目配置等等。 |
| 26 | + |
| 27 | +## 例子介绍 |
| 28 | +本文的例子是取自我的side project之中,日报(report)的查询,试图利用Redis作为缓存,优化查询效率。 |
| 29 | + |
| 30 | +## 知识点解析 |
| 31 | +### 1. 自定义配置 |
| 32 | +Spring Boot允许外化配置,这样你可以在不同的环境下使用相同的代码。你可以使用properties文件、yaml文件,环境变量和命令行参数来外化配置。使用@Value注解,可以直接将属性值注入到你的beans中。 |
| 33 | +Spring Boot使用一个非常特别的PropertySource来允许对值进行合理的覆盖,按照优先考虑的顺序排位如下: |
| 34 | +``` |
| 35 | +1. 命令行参数 |
| 36 | +2. 来自java:comp/env的JNDI属性 |
| 37 | +3. Java系统属性(System.getProperties()) |
| 38 | +4. 操作系统环境变量 |
| 39 | +5. 只有在random.*里包含的属性会产生一个RandomValuePropertySource |
| 40 | +6. 在打包的jar外的应用程序配置文件(application.properties,包含YAML和profile变量) |
| 41 | +7. 在打包的jar内的应用程序配置文件(application.properties,包含YAML和profile变量) |
| 42 | +8. 在@Configuration类上的@PropertySource注解 |
| 43 | +9. 默认属性(使用SpringApplication.setDefaultProperties指定) |
| 44 | +``` |
| 45 | +**使用场景**:可以将一个application.properties打包在Jar内,用来提供一个合理的默认name值;当运行在生产环境时,可以在Jar外提供一个application.properties文件来覆盖name属性;对于一次性的测试,可以使用特病的命令行开关启动,而不需要重复打包jar包。 |
| 46 | + |
| 47 | +具体的例子操作过程如下: |
| 48 | + |
| 49 | +- 新建配置文件(application.properties) |
| 50 | +``` |
| 51 | +spring.redis.database=0 |
| 52 | +spring.redis.host=localhost |
| 53 | +spring.redis.password= # Login password of the redis server. |
| 54 | +spring.redis.pool.max-active=8 |
| 55 | +spring.redis.pool.max-idle=8 |
| 56 | +spring.redis.pool.max-wait=-1 |
| 57 | +spring.redis.pool.min-idle=0 |
| 58 | +spring.redis.port=6379 |
| 59 | +spring.redis.sentinel.master= # Name of Redis server. |
| 60 | +spring.redis.sentinel.nodes= # Comma-separated list of host:port pairs. |
| 61 | +spring.redis.timeout=0 |
| 62 | +``` |
| 63 | + - 使用@PropertySource引入配置文件 |
| 64 | + |
| 65 | +``` |
| 66 | +@Configuration |
| 67 | +@PropertySource(value = "classpath:/redis.properties") |
| 68 | +@EnableCaching |
| 69 | +public class CacheConfig extends CachingConfigurerSupport { |
| 70 | + ...... |
| 71 | +} |
| 72 | +``` |
| 73 | + - 使用@Value引用属性值 |
| 74 | + |
| 75 | +``` |
| 76 | +@Configuration |
| 77 | +@PropertySource(value = "classpath:/redis.properties") |
| 78 | +@EnableCaching |
| 79 | +public class CacheConfig extends CachingConfigurerSupport { |
| 80 | + @Value("${spring.redis.host}") |
| 81 | + private String host; |
| 82 | + @Value("${spring.redis.port}") |
| 83 | + private int port; |
| 84 | + @Value("${spring.redis.timeout}") |
| 85 | + private int timeout; |
| 86 | + ...... |
| 87 | +} |
| 88 | +``` |
| 89 | + |
| 90 | + |
| 91 | +### 2. redis使用 |
| 92 | +- 添加pom配置 |
| 93 | + |
| 94 | +``` |
| 95 | +<dependency> |
| 96 | + <groupId>org.springframework.boot</groupId> |
| 97 | + <artifactId>spring-boot-starter-redis</artifactId> |
| 98 | +</dependency> |
| 99 | +``` |
| 100 | +- 编写CacheConfig |
| 101 | + |
| 102 | +``` |
| 103 | +@Configuration |
| 104 | +@PropertySource(value = "classpath:/redis.properties") |
| 105 | +@EnableCaching |
| 106 | +public class CacheConfig extends CachingConfigurerSupport { |
| 107 | + @Value("${spring.redis.host}") |
| 108 | + private String host; |
| 109 | + @Value("${spring.redis.port}") |
| 110 | + private int port; |
| 111 | + @Value("${spring.redis.timeout}") |
| 112 | + private int timeout; |
| 113 | + @Bean |
| 114 | + public KeyGenerator wiselyKeyGenerator(){ |
| 115 | + return new KeyGenerator() { |
| 116 | + @Override |
| 117 | + public Object generate(Object target, Method method, Object... params) { |
| 118 | + StringBuilder sb = new StringBuilder(); |
| 119 | + sb.append(target.getClass().getName()); |
| 120 | + sb.append(method.getName()); |
| 121 | + for (Object obj : params) { |
| 122 | + sb.append(obj.toString()); |
| 123 | + } |
| 124 | + return sb.toString(); |
| 125 | + } |
| 126 | + }; |
| 127 | + } |
| 128 | + @Bean |
| 129 | + public JedisConnectionFactory redisConnectionFactory() { |
| 130 | + JedisConnectionFactory factory = new JedisConnectionFactory(); |
| 131 | + factory.setHostName(host); |
| 132 | + factory.setPort(port); |
| 133 | + factory.setTimeout(timeout); //设置连接超时时间 |
| 134 | + return factory; |
| 135 | + } |
| 136 | + @Bean |
| 137 | + public CacheManager cacheManager(RedisTemplate redisTemplate) { |
| 138 | + RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate); |
| 139 | + // Number of seconds before expiration. Defaults to unlimited (0) |
| 140 | + cacheManager.setDefaultExpiration(10); //设置key-value超时时间 |
| 141 | + return cacheManager; |
| 142 | + } |
| 143 | + @Bean |
| 144 | + public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) { |
| 145 | + StringRedisTemplate template = new StringRedisTemplate(factory); |
| 146 | + setSerializer(template); //设置序列化工具,这样ReportBean不需要实现Serializable接口 |
| 147 | + template.afterPropertiesSet(); |
| 148 | + return template; |
| 149 | + } |
| 150 | + private void setSerializer(StringRedisTemplate template) { |
| 151 | + Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); |
| 152 | + ObjectMapper om = new ObjectMapper(); |
| 153 | + om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); |
| 154 | + om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); |
| 155 | + jackson2JsonRedisSerializer.setObjectMapper(om); |
| 156 | + template.setValueSerializer(jackson2JsonRedisSerializer); |
| 157 | + } |
| 158 | +} |
| 159 | +``` |
| 160 | +- 启动缓存,使用@Cacheable注解在需要缓存的接口上即可 |
| 161 | + |
| 162 | +``` |
| 163 | +@Service |
| 164 | +public class ReportService { |
| 165 | + @Cacheable(value = "reportcache", keyGenerator = "wiselyKeyGenerator") |
| 166 | + public ReportBean getReport(Long id, String date, String content, String title) { |
| 167 | + System.out.println("无缓存的时候调用这里---数据库查询"); |
| 168 | + return new ReportBean(id, date, content, title); |
| 169 | + } |
| 170 | +} |
| 171 | +``` |
| 172 | +- 测试验证 |
| 173 | + - 运行方法如下: |
| 174 | + - mvn clean package |
| 175 | + - java -jar target/dailyReport-1.0-SNAPSHOT.jar |
| 176 | + - 验证缓存起作用: |
| 177 | + - 访问:http://localhost:8080/report/test |
| 178 | + - 访问:http://localhost:8080/report/test2 |
| 179 | + - 验证缓存失效(10s+后执行): |
| 180 | + - 访问:http://localhost:8080/report/test2 |
| 181 | + |
| 182 | +##参考资料 |
| 183 | +1. [spring boot quick start](http://projects.spring.io/spring-boot/#quick-start) |
| 184 | +2. [Spring Boot参考指南](https://www.gitbook.com/book/qbgbook/spring-boot-reference-guide-zh/details) |
| 185 | +3. [Spring Boot Reference Guide(1.3.0-REALEASE)](http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/) |
| 186 | +4. [Getting Started Guides](http://spring.io/guides) |
| 187 | +5. [Caching Data in Spring Using Redis](http://caseyscarborough.com/blog/2014/12/18/caching-data-in-spring-using-redis/) |
| 188 | +6. [Spring boot使用Redis做缓存](http://wiselyman.iteye.com/blog/2184884) |
| 189 | +7. [redis设计与实现](http://redisbook.com/index.html) |
0 commit comments