Spring 的骨骼架构
Spring 总共有十几个组件,但是真正核心的组件只有几个,下面是 Spring 框架的总体架构图:
图 1 .Spring 框架的总体架构图

从上图中可以看出 Spring 框架中的核心组件只有三个:Core、Context 和 Beans。它们构建起了整个 Spring 的骨骼架构。没有它们就不可能有 AOP、Web 等上层的特性功能。下面也将主要从这三个组件入手分析 Spring。
Spring 总共有十几个组件,但是真正核心的组件只有几个,下面是 Spring 框架的总体架构图:
从上图中可以看出 Spring 框架中的核心组件只有三个:Core、Context 和 Beans。它们构建起了整个 Spring 的骨骼架构。没有它们就不可能有 AOP、Web 等上层的特性功能。下面也将主要从这三个组件入手分析 Spring。
Spring Data Redis 的 RedisTemplate 对 Redis 进行了封装。在对某值调用increment()方法时报错:
redis ERR value is not an integer or out of range
redisTemplate.opsForValue().increment(key);
大家都知道redis序列化是将key,value值先转换为流的形式,再存储到redis中。
RedisTemplate是使用的JdkSerializationRedisSerializer序列化,序列化后的值包含了对象信息,版本号,类信息等,是一串字符串,所以无法进行数值自增操作。
而StringRedisTemplate序列化策略是字符串的值直接转为字节数组,所以存储到redis中是数值,所以可以进行自增操作。
对应用开发者来说,Java 持久化 APIJava Persistence API(JPA)是一项重要的 java 功能,需要透彻理解。它为 Java 开发人员定义了如何将对象的方法调用转换为访问、持久化及管理存储在 NoSQL 和关系型数据库中的数据的方案。
本文通过构建自行车借贷服务的教程示例来详细研究 JPA。此示例会使用 Spring Boot 框架、MongoDB 数据库(已经不开源)和 Maven 包管理来构建一个大型应用程序,并且构建一个创建、读取、更新和删除(CRUD)层。这儿我选择 NetBeans 11 作为我的 IDE。
此教程仅从开源的角度来介绍 Java 持久化 API 的工作原理,不涉及其作为工具的使用说明。这全是关于编写应用程序模式的学习,但对于理解具体的软件实现也很益处。可以从我的 GitHub 仓库来获取相关代码。
Java 是一门面向对象的编程语言,自 1996 年发布第一版 Java 开发工具(JDK)起,已经变化了很多很多。要了解其各种发展及其虚拟机本身就是一堂历史课。简而言之,和 Linux 内核很相似,自发布以来,该语言已经向多个方向分支发展。有对社区免费的标准版本、有针对企业的企业版本及由多家供应商提供的开源替代品。主要版本每六个月发布一次,其功能往往差异很大,所以确认选用版本前得先做些研究。
总而言之,Java 的历史很悠久。本教程重点介绍 Java 11 的开源实现 JDK 11。因其是仍然有效的长期支持版本之一。
POM.xml
文件来管理包及其依赖项。如果你使用过 NPM 的话,可能会非常熟悉包管理器的功能。此外 Maven 也用来进行项目构建及生成功能报告。我们会用这组工具为一个虚构自行车商店创建一个简单的应用程序。会实现对 Customer
和 Bike
对象集合的的插入操作。
Spring Cloud 开发团队昨日公布了 Spring Cloud 2020 年的路线图,并对 Spring Cloud Greenwich 和 Hoxton 的生命周期进行了一些讲解。
开发团队称 Spring Cloud Ilford 将是下一个主要版本,这也将是自 Spring Cloud Finchley 发布以来的第一个主要版本。此版本将提供对 Spring Boot 2.x 和 Spring Framework 5.x 的支持。通过使 Ilford 成为主要版本,开发团队将能够删除进入维护模式(maintenance mode)的模块,并兑现今年早些时候宣布的简化新版本的承诺。此外,团队成员还会对一些 API 进行重构,这可能会引入重大变更。
Spring Cloud Ilford 将在 2020 年第四季度的某个时候随 Spring Framework 5.3 和 Spring Boot 2.4 一起发布。
把原生Http Connection改为使用Feign请求调用外部接口,在方法上添加注解:
@PostMapping("{接口url}")
@Headers({"Content-Type: application/json"})
返回:
看来用@Headers设置的Content-Type没有生效。@Headers是Feign自带的注册,而@PostMapping是Spring MVC的注解。在@PostMapping中也有header属性,于是改为:
@PostMapping(value = "{接口url}", headers = {"Content-Type: application/json"})
问题依旧。
除去properties文件路径错误、拼写错误外,出现”Could not resolve placeholder”很有可能是使用了多个PropertyPlaceholderConfigurer或者多个<context:property-placeholder>的原因。 一定要记住,不管是在一个Spring文件还是在多个Spring文件被统一load的情况下,直接写:
<context:property-placeholder location=""/>
<context:property-placeholder location=""/>
是错误的!
项目中涉及到复杂查询,比如模糊查询。ORM框架往往不能很好处理,难免会遇到拼接字符串。而手动拼接的方式很容易让代码产生SQL注入漏洞。使用拦截器和过滤器,过滤请求中的危险字符,可以解决SQL注入攻击。
常用的请求有两种方式,一种是form表单提交,另一种是json格式。在Spring框架中处理这两种的方法也是有区别的。
过滤form表单
过滤表单提交的危险字符,使用的是过滤器,需要继承OncePerRequestFilter类。
在spring中,filter都默认继承OncePerRequestFilter。顾名思义,他能够确保在一次请求只通过一次filter,而不需要重复执行。
大家常识上都认为,一次请求本来就只过一次,为什么还要由此特别限定呢,实际上我们常识和实际的实现并不真的一样,经过一番查阅后,此方式是为了兼容不同的web container,特意而为之(jsr168),也就是说并不是所有的container都像我们期望的只过滤一次,servlet版本不同,表现也不同。
/**
* Filter base class that guarantees to be just executed once per request,
* on any servlet container. It provides a {@link #doFilterInternal}
* method with HttpServletRequest and HttpServletResponse arguments.
*
* <p>The {@link #getAlreadyFilteredAttributeName} method determines how
* to identify that a request is already filtered. The default implementation
* is based on the configured name of the concrete filter instance.
*
* @author Juergen Hoeller
* @since 06.12.2003
*/
如,servlet2.3与servlet2.4也有一定差异
在servlet-2.3中,Filter会过滤一切请求,包括服务器内部使用forward转发请求和<%@ include file="/index.jsp"%>的情况。
到了servlet-2.4中Filter默认下只拦截外部提交的请求,forward和include这些内部转发都不会被过滤,但是有时候我们需要 forward的时候也用到Filter。
因此,为了兼容各种不同的运行环境和版本,默认filter继承OncePerRequestFilter是一个比较稳妥的选择。
以下是我的过滤器代码:
构建基于Spring Boot 2.X应用,使用Cache,需要引入:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
以前开发Spring用EhCache来做缓存。在做集群或分布式时,还是Redis比较好用。引入Spring Data Redis如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
注意这里会有jedis依赖。
在applicatin.yml配置Redis和Cache:
spring:
cache:
redis:
cache-names:
cache-null-values: false
key-prefix: spring:cache
time-to-live: 0
use-key-prefix: true
type: # Cache type. By default, auto-detected according to the environment.
redis:
database: 5
url: # Connection URL. Overrides host, port, and password. User is ignored. Example: redis://user:password@example.com:6379
host: 127.0.0.1
port: 6379
password:
timeout: 3000
jedis:
pool:
max-active: 200
max-idle: 10
max-wait: -1
min-idle: 0
更多配置属性可参考Spring Boot官方说明:
新建RedisConfig类,增加如下方法:
/**
* 定义缓存数据 key 生成策略的bean
* 包名+类名+方法名+所有参数
* @return
*/
@Bean
public KeyGenerator wiselyKeyGenerator(){
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder buff = new StringBuilder();
buff.append(target.getClass().getName());
buff.append(method.getName());
for (Object obj : params) {
buff.append(obj.toString());
}
return buff.toString();
}
};
}
在Spring Boot中引入ZooKeeper的jar包,启动时报错,如图:
是slf4j日志包冲出导致,因为项目在spring-boot-starter-logging中已引入。
解决办法,排除ZooKeeper中slf4j的依赖:
<dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>${zookeeper.version}</version> <exclusions> <exclusion> <artifactId>slf4j-log4j12</artifactId> <groupId>org.slf4j</groupId> </exclusion> </exclusions> </dependency>
参考:https://blog.csdn.net/change987654321/article/details/82800279
SpringBoot做文件上传时出现了The field file exceeds its maximum permitted size of 1048576 bytes.错误,显示文件的大小超出了允许的范围。查看了官方文档,原来Spring Boot工程嵌入的tomcat限制了请求的文件大小,这一点在Spring Boot的官方文档中有说明,原文如下:
文档说明表示,每个文件的配置最大为1Mb,单次请求的文件的总数不能大于10Mb。要更改这个默认值需要在配置文件(如application.properties)中加入两个配置。
需要设置以下两个参数
multipart.maxFileSize
multipart.maxRequestSize