Spring Boot lets you externalize your configuration so that you can work with the same application code in different environments. You can use a variety of external configuration sources, include Java properties files, YAML files, environment variables, and command-line arguments.
Property values can be injected directly into your beans by
using the @Value annotation, accessed through Spring’s Environment abstraction,
Spring Boot uses a very particular PropertySource order that is designed to allow sensible overriding of values. Later property sources can override the values defined in earlier ones. Sources are considered in the following order:
Default properties (specified by setting SpringApplication.setDefaultProperties).
It is recommended to stick with one format for your entire application. If you have configuration files with both .properties and .yml format in the same location, .properties takes precedence.
Spring Boot will automatically find and load application.properties and application.yaml files from the following locations when your application starts:
From the classpath
The classpath root
The classpath /config package
From the current directory
The current directory
The config/ subdirectory in the current directory
Immediate child directories of the config/ subdirectory
The list is ordered by precedence (with values from lower items overriding earlier ones). Documents from the loaded files are added as PropertySources to the Spring Environment.
spring.config.name 修改配置文件名称:
If you do not like application as the configuration file name, you can switch to another file name by specifying a spring.config.name environment property.
For example, to look for myproject.properties and myproject.yaml files you can run your application as follows:
You can also refer to an explicit location by using the spring.config.location environment property. This property accepts a comma-separated list of one or more locations to check.
The following example shows how to specify two distinct files:
Use the prefix optional: if the locations are optional and you do not mind if they do not exist.
配置嵌入式服务器
Spring Boot 集成了 Tomcat、Jetty 和 Undertow,极大便利了项目部署。下面介绍一些常用配置:
1 2
server.port=8080 # Server HTTP port. server.context-path= # Context path
Tomcat
URI 编码配置:
1
server.tomcat.uri-encoding=UTF-8 # Character encoding to use to decode the URI.
代理配置:
1 2 3
server.tomcat.remote-ip-header= # Name of the http header from which the remote ip is extracted. For instance `X-FORWARDED-FOR` server.tomcat.protocol-header= # Header that holds the incoming protocol, usually named "X-Forwarded-Proto". server.tomcat.port-header=X-Forwarded-Port # Name of the HTTP header used to override the original port value.
Socket 连接限制及等待超时时间:
1 2
server.tomcat.max-connections= # Maximum number of connections that the server will accept and process at any given time. server.connection-timeout= # Time in milliseconds that connectors will wait for another HTTP request before closing the connection. When not set, the connector's container-specific default will be used. Use a value of -1 to indicate no (i.e. infinite) timeout.
业务线程池调优:
1 2 3
server.tomcat.max-threads=0 # Maximum amount of worker threads. Default 200. server.tomcat.min-spare-threads=0 # Minimum amount of worker threads. server.tomcat.accept-count= # Maximum queue length for incoming connection requests when all possible request processing threads are in use.
Endpoints Actuator endpoints allow you to monitor and interact with your application. Spring Boot includes a number of built-in endpoints and you can also add your own. For example the health endpoint provides basic application health information. Run up a basic application and look at /actuator/health.
Metrics Spring Boot Actuator provides dimensional metrics by integrating with Micrometer.
Audit Spring Boot Actuator has a flexible audit framework that will publish events to an AuditEventRepository. Once Spring Security is in play it automatically publishes authentication events by default. This can be very useful for reporting, and also to implement a lock-out policy based on authentication failures.
spring-boot-devtools
热部署、静态资源 livereload 等等。
spring-boot-tools 工具集的父 POM。为 Spring Boot 开发者提供的常用工具集。例如:
<dependencyManagement> <dependencies> <dependency> <!-- Import dependency management from Spring Boot --> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.0.1.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
这种组合方式能解决 Maven 单继承问题。
引入 spring-boot-maven-plugin
The Spring Boot Maven Plugin provides Spring Boot support in Apache Maven. It allows you to package executable jar or war archives, run Spring Boot applications, generate build information and start your Spring Boot application prior to running integration tests.
Repackage existing JAR and WAR archives so that they can be executed from the command line using java -jar. With layout=NONE can also be used simply to package a JAR with nested dependencies (and no main class, so not executable).
Start a spring application. Contrary to the run goal, this does not block and allows other goals to operate on the application. This goal is typically used in integration test scenario where the application is started before a test suite and stopped after.
We can configure the Spring Boot Maven Plugin in our pom.xml to repackage the artifact during the package phase of the Maven lifecycle. In other words, when we execute mvn package, the spring-boot:repackage will be automatically executed.
The configuration is pretty straightforward. We just add the repackage goal to an execution element:
In addition to running Spring Boot applications by using java -jar, it is also possible to make fully executable applications for Unix systems. A fully executable jar can be executed like any other executable binary or it can be registered with init.d or systemd. This helps when installing and managing Spring Boot applications in common production environments.
⚠️ Caution
Fully executable jars work by embedding an extra script at the front of the file. It is recommended that you make your jar or war fully executable only if you intend to execute it directly, rather than running it with java -jar or deploying it to a servlet container.
To create a ‘fully executable’ jar with Maven, use the following plugin configuration:
You can then run your application by typing ./my-application.jar (where my-application is the name of your artifact). The directory containing the jar is used as your application’s working directory.
With the exception of JARFILE and APP_NAME, the settings listed in the preceding section can be configured by using a .conf file. The file is expected to be next to the jar file and have the same name but suffixed with .conf rather than .jar. For example, a jar named /var/myapp/myapp.jar uses the configuration file named /var/myapp/myapp.conf, as shown in the following example:
GET 请求、POST 表单时,对方 Controller 方法入参需标注 @RequestParam,以接收 query parameter。但要注意,官方文档提醒如下:
Supported for annotated handler methods in Spring MVC and Spring WebFlux as follows:
In Spring MVC, “request parameters” map to query parameters, form data, and parts in multipart requests. This is because the Servlet API combines query parameters and form data into a single map called “parameters”, and that includes automatic parsing of the request body.
In Spring WebFlux, “request parameters” map to query parameters only. To work with all 3, query, form data, and multipart data, you can use data binding to a command object annotated with ModelAttribute.
CURL 形式
GET 请求
1 2
curl --location --request GET 'http://rootUrl/path?key=value' \ --header 'Content-Type: application/x-www-form-urlencoded'
Synchronous client to perform HTTP requests, exposing a simple, template method API over underlying HTTP client libraries such as the JDK HttpURLConnection, Apache HttpComponents, and others.
The RestTemplate offers templates for common scenarios by HTTP method, in addition to the generalized exchange and execute methods that support of less frequent cases.
Class URL represents a Uniform Resource Locator, a pointer to a “resource” on the World Wide Web. A resource can be something as simple as a file or a directory, or it can be a reference to a more complicated object, such as a query to a database or to a search engine. More information on the types of URLs and their formats can be found at: Types of URL
The abstract class URLConnection is the superclass of all classes that represent a communications link between the application and a URL. Instances of this class can be used both to read from and to write to the resource referenced by the URL.
This class implements client sockets (also called just “sockets”). A socket is an endpoint for communication between two machines.
The actual work of the socket is performed by an instance of the SocketImpl class. An application, by changing the socket factory that creates the socket implementation, can configure itself to create sockets appropriate to the local firewall.
The abstract class SocketImpl is a common superclass of all classes that actually implement sockets. It is used to create both client and server sockets.
Instances of the file descriptor class serve as an opaque handle to the underlying machine-specific structure representing an open file, an open socket, or another source or sink of bytes. The main practical use for a file descriptor is to create a FileInputStream or FileOutputStream to contain it.
Applications should not create their own file descriptors.
In case the TCP handshakes are not complete, the connection remains unsuccessful. Consequently, the program throws an IOException indicating an error occurred while establishing a new connection.
Signals that an error occurred while attempting to bind a socket to a local address and port.
问题:
1 2 3 4 5 6 7
java.net.BindException: Address already in use (Bind failed) at java.net.PlainSocketImpl.socketBind(Native Method) at java.net.AbstractPlainSocketImpl.bind(AbstractPlainSocketImpl.java:513) at java.net.ServerSocket.bind(ServerSocket.java:375) at java.net.ServerSocket.<init>(ServerSocket.java:237) at java.net.ServerSocket.<init>(ServerSocket.java:181) ...
Signals that an error occurred while attempting to connect a socket to a remote address and port.
Connection refused
问题:
1 2 3 4 5 6 7 8 9 10 11
java.net.ConnectException: Connection refused (Connection refused) at java.net.PlainSocketImpl.socketConnect(Native Method) at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:476) at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:218) at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:200) at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:394) at java.net.Socket.connect(Socket.java:606) at java.net.Socket.connect(Socket.java:555) at java.net.Socket.<init>(Socket.java:451) at java.net.Socket.<init>(Socket.java:228) ...
java.net.ConnectException: Connection timed out (Connection timed out) at java.net.PlainSocketImpl.socketConnect(Native Method) at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350) at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206) at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188) at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) at java.net.Socket.connect(Socket.java:589) at java.net.Socket.connect(Socket.java:538) at java.net.Socket.<init>(Socket.java:434) at java.net.Socket.<init>(Socket.java:211) ...
Sometimes, firewalls block certain ports due to security reasons. As a result, a “connection timed out” error can occur when a client is trying to establish a connection to a server. Therefore, we should check the firewall settings to see if it’s blocking a port before binding it to a service.
Signals that a timeout has occurred on a socket accept() or read().
Accept timed out
问题:
1 2 3 4 5 6
java.net.SocketTimeoutException: Accept timed out at java.net.PlainSocketImpl.socketAccept(Native Method) at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:535) at java.net.ServerSocket.implAccept(ServerSocket.java:545) at java.net.ServerSocket.accept(ServerSocket.java:513) ...
原因:server-side accept() 超时:
1 2
ServerSocketserverSocket=newServerSocket(port, backlog); serverSocket.setSoTimeout(5 * 1000); // timeout for accept()
Read timed out
问题:
1 2 3 4 5 6 7
java.net.SocketTimeoutException: Read timed out at java.net.SocketInputStream.socketRead0(Native Method) at java.net.SocketInputStream.socketRead(SocketInputStream.java:116) at java.net.SocketInputStream.read(SocketInputStream.java:171) at java.net.SocketInputStream.read(SocketInputStream.java:141) at java.net.SocketInputStream.read(SocketInputStream.java:127) ...
Thrown to indicate that there is an error creating or accessing a Socket.
Connection reset by peer
1 2 3 4 5 6 7 8
java.net.SocketException: Connection reset by peer (connect failed) at java.net.PlainSocketImpl.socketConnect(Native Method) at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:476) at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:218) at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:200) at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:394) at java.net.Socket.connect(Socket.java:606) ...
Bad file descriptor
1 2 3 4 5
java.net.SocketException: Bad file descriptor (Write failed) at java.net.SocketOutputStream.socketWrite0(Native Method) at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:111) at java.net.SocketOutputStream.write(SocketOutputStream.java:155) ...
Broken pipe
1 2 3 4 5
java.net.SocketException: Broken pipe (Write failed) at java.net.SocketOutputStream.socketWrite0(Native Method) at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:111) at java.net.SocketOutputStream.write(SocketOutputStream.java:155) ...
通过在代理类中包裹切面,Spring 在运行期把切面织入到 Spring 管理的 bean 中。如下图所示,代理类封装了目标类,并拦截被通知方法的调用,再把调用转发给真正的目标 bean。当代理拦截到方法调用时,在调用目标 bean 方法之前,会执行切面逻辑。
直到应用需要被代理的 bean 时,Spring 才创建代理对象。如果使用的是 ApplicationContext 的话,在 ApplicationContext 从 BeanFactory 中加载所有 bean 的时候,Spring 才会创建被代理的对象。因为 Spring 运行时才创建代理对象,所以我们不需要特殊的编译器来织入 Spring AOP 的切面。
Advice 使用 Java 编写,使用成本低
Spring 所创建的通知(Advice)都是用标准的 Java 类编写的。这样的话,我们就可以使用与普通 Java 开发一样的集成开发环境(IDE)来开发切面。而且,定义通知所应用的切点通常会使用注解或在 Spring 配置文件里采用 XML 来编写,这两种语法对于Java开发者来说都是相当熟悉的。
finalclassJdkDynamicAopProxyimplementsAopProxy, InvocationHandler, Serializable { /** * 创建基于接口的 JDK 动态代理 **/ @Override public Object getProxy(ClassLoader classLoader) { if (logger.isDebugEnabled()) { logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource()); } Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true); findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); } /** * Implementation of {@code InvocationHandler.invoke}. */ @Override public Object invoke(Object proxy, Method method, Object[] args)throws Throwable { ... // Get the interception chain for this method. List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); ... // We need to create a method invocation... invocation = newReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); // Proceed to the joinpoint through the interceptor chain. retVal = invocation.proceed(); ... } }
官方文档的一些关键摘录:
AOP Proxies
Spring AOP defaults to using standard JDK dynamic proxies for AOP proxies. This enables any interface (or set of interfaces) to be proxied.
Spring AOP can also use CGLIB proxies. This is necessary to proxy classes rather than interfaces. By default, CGLIB is used if a business object does not implement an interface. As it is good practice to program to interfaces rather than classes, business classes normally implement one or more business interfaces. It is possible to force the use of CGLIB, in those (hopefully rare) cases where you need to advise a method that is not declared on an interface or where you need to pass a proxied object to a method as a concrete type.
It is important to grasp the fact that Spring AOP is proxy-based. See Understanding AOP Proxies for a thorough examination of exactly what this implementation detail actually means.
Proxying Mechanisms
Spring AOP uses either JDK dynamic proxies or CGLIB to create the proxy for a given target object. (JDK dynamic proxies are preferred whenever you have a choice).
If the target object to be proxied implements at least one interface, a JDK dynamic proxy is used. All of the interfaces implemented by the target type are proxied. If the target object does not implement any interfaces, a CGLIB proxy is created.
If you want to force the use of CGLIB proxying (for example, to proxy every method defined for the target object, not only those implemented by its interfaces), you can do so. However, you should consider the following issues:
final methods cannot be advised, as they cannot be overridden.
As of Spring 3.2, it is no longer necessary to add CGLIB to your project classpath, as CGLIB classes are repackaged under org.springframework and included directly in the spring-core JAR. This means that CGLIB-based proxy support “just works”, in the same way that JDK dynamic proxies always have.
As of Spring 4.0, the constructor of your proxied object is NOT called twice any more, since the CGLIB proxy instance is created through Objenesis. Only if your JVM does not allow for constructor bypassing, you might see double invocations and corresponding debug log entries from Spring’s AOP support.
To force the use of CGLIB proxies, set the value of the proxy-target-class attribute of the <aop:config> element to true, as follows:
1 2 3
<aop:configproxy-target-class="true"> <!-- other beans defined here... --> </aop:config>
To force CGLIB proxying when you use the @AspectJ auto-proxy support, set the proxy-target-class attribute of the <aop:aspectj-autoproxy> element to true, as follows:
The @AspectJ support can be enabled with XML- or Java-style configuration. In either case, you also need to ensure that AspectJ’s aspectjweaver.jar library is on the classpath of your application (version 1.8 or later).
Typically used within web applications that require some programmatic initialization of the application context. For example, registering property sources or activating profiles against the context’s environment.
T getObject()// Return an instance (possibly shared or independent) of the object managed by this factory. Class<?> getObjectType() // Return the type of object that this FactoryBean creates, or null if not known in advance. booleanisSingleton()// Is the object managed by this factory a singleton? That is, will getObject() always return the same object (a reference that can be cached)?
Indicates that an annotated class is a “component”. Such classes are considered as candidates for auto-detection when using annotation-based configuration and classpath scanning. Other class-level annotations may be considered as identifying a component as well, typically a special kind of component: e.g. the @Repository annotation or AspectJ’s @Aspect annotation.
Configures component scanning directives for use with @Configuration classes. Provides support parallel with Spring XML’s <context:component-scan> element. Either basePackageClasses() or basePackages() (or its alias value()) may be specified to define specific packages to scan. If specific packages are not defined, scanning will occur from the package of the class that declares this annotation. Note that the <context:component-scan> element has an annotation-config attribute; however, this annotation does not. This is because in almost all cases when using @ComponentScan, default annotation config processing (e.g. processing @Autowired and friends) is assumed. Furthermore, when using AnnotationConfigApplicationContext, annotation config processors are always registered, meaning that any attempt to disable them at the @ComponentScan level would be ignored. See @Configuration‘s Javadoc for usage examples.
Annotation support for the Application Context, including JSR-250 “common” annotations, component-scanning, and Java-based metadata for creating Spring-managed objects.
XmlWebApplicationContext 从 Web 应用下的一个或多个 XML 配置文件中加载上下文定义,是 Web 应用程序使用的默认上下文类,因此不必在 web.xml 文件中显式指定这个上下文类。以下代码描述了 web.xml 中指向将由 ContextLoaderListener 监听器类载入的外部 XML 上下文文件的元素: