Tag Archives: Spring Boot

[Solved] The length of the data truncation done by springboothinesdata for the column.

Questions

According to the error report, the field defined in the database is too short to store new data

Solution

  @Column(length = 3000)
  private String cellExcel;

Manually define the length of the field, but it will not take effect on the existing table, so you still need to use SQL statements to manually modify the length of the table field, that is:

ALTER TABLE mydb.form_template_field MODIFY COLUMN cell_excel VARCHAR(3000);

 

An exception solution of mongodb prematurely reached end of stream in spring boot

MongoDB is used in the spring boot project. When MongoDB is not operated for a period of time, an exception will occur when MongoDB is operated next time. The exception is as follows:

org.springframework.data.mongodb.UncategorizedMongoDbException: Prematurely reached end of stream; nested exception is com.mongodb.MongoSocketReadException: Prematurely reached end of stream
        at org.springframework.data.mongodb.core.MongoExceptionTranslator.translateExceptionIfPossible(MongoExceptionTranslator.java: 107 )
        at org.springframework.data.mongodb.core.MongoTemplate.potentiallyConvertRuntimeException(MongoTemplate.java: 2146 )
        at org.springframework.data.mongodb.core.MongoTemplate.executeFindOneInternal(MongoTemplate.java: 1928 )
        at org.springframework.data.mongodb.core.MongoTemplate.doFindOne(MongoTemplate.java: 1736 )
        at org.springframework.data.mongodb.core.MongoTemplate.findOne(MongoTemplate.java: 606 )
        at org.springframework.data.mongodb.core.MongoTemplate.findOne(MongoTemplate.java: 601 )
        at com.lwli.service.impl.SessionServiceImpl.findOneSessionByCustomerIdAndStatus(SessionServiceImpl.java: 51 ) 
        at java.lang.Thread.run(Thread.java: 745 )
Caused by: com.mongodb.MongoSocketReadException: Prematurely reached end of stream
        at com.mongodb.connection.SocketStream.read(SocketStream.java: 88 )
        at com.mongodb.connection.InternalStreamConnection.receiveResponseBuffers(InternalStreamConnection.java: 494 )
        at com.mongodb.connection.InternalStreamConnection.receiveMessage(InternalStreamConnection.java: 224 )
        at com.mongodb.connection.UsageTrackingInternalConnection.receiveMessage(UsageTrackingInternalConnection.java: 96 )
        at com.mongodb.connection.DefaultConnectionPool$PooledConnection.receiveMessage(DefaultConnectionPool.java: 440 )
        at com.mongodb.connection.QueryProtocol.execute(QueryProtocol.java: 289 )
        at com.mongodb.connection.QueryProtocol.execute(QueryProtocol.java: 54 )
        at com.mongodb.connection.DefaultServer$DefaultServerProtocolExecutor.execute(DefaultServer.java: 168 )
        at com.mongodb.connection.DefaultServerConnection.executeProtocol(DefaultServerConnection.java: 289 )
        at com.mongodb.connection.DefaultServerConnection.query(DefaultServerConnection.java: 212 )
        at com.mongodb.operation.FindOperation$ 1.call(FindOperation.java:525 )
        at com.mongodb.operation.FindOperation$ 1.call(FindOperation.java:510 )
        at com.mongodb.operation.OperationHelper.withConnectionSource(OperationHelper.java: 435 )
        at com.mongodb.operation.OperationHelper.withConnection(OperationHelper.java: 408 )
        at com.mongodb.operation.FindOperation.execute(FindOperation.java: 510 )
        at com.mongodb.operation.FindOperation.execute(FindOperation.java: 81 )
        at com.mongodb.Mongo.execute(Mongo.java: 836 )
        at com.mongodb.Mongo$ 2.execute(Mongo.java:823 )
        at com.mongodb.DBCursor.initializeCursor(DBCursor.java: 870 )
        at com.mongodb.DBCursor.hasNext(DBCursor.java: 142 )
        at com.mongodb.DBCursor.one(DBCursor.java: 679 )
        at com.mongodb.DBCollection.findOne(DBCollection.java: 833 )
        at com.mongodb.DBCollection.findOne(DBCollection.java: 796 )
        at com.mongodb.DBCollection.findOne(DBCollection.java: 743 )
        at org.springframework.data.mongodb.core.MongoTemplate$FindOneCallback.doInCollection(MongoTemplate.java: 2197 )
        at org.springframework.data.mongodb.core.MongoTemplate$FindOneCallback.doInCollection(MongoTemplate.java: 2181 )
        at org.springframework.data.mongodb.core.MongoTemplate.executeFindOneInternal(MongoTemplate.java: 1925 )
        ... 12 more

 

I searched the Internet and found that there are many reasons for this problem. The main reasons may be connection timeout, reading and writing timeout, etc., according to others’ tips, set

socketKeepAlive = true;
socketTimeout = 30000;

However, it didn’t work. When I visited MongoDB again after a period of time, abnormalities still appeared. When I searched on Google, I found an article https://studio3t.com/whats-new/how-to-prevent-your-connection-from-dropping-with-hosted-mongodb-instances/, which mentioned one point above, when When the connection is idle for a period of time, the connection is closed due to firewall or load balancing, and the client does not know that it will make an error when the client continues to use the closed connection for reading and writing.

The solution is to set the connection idle time. When this idle time is exceeded, the client actively closes the connection and re-establishes the connection when it is used next time, which can effectively avoid the problem of connection failure.

Configure the bean of MongoClientOptions in spring boot. For example, set the maximum idle time to 6000ms.

@Configuration
 public  class WechatMpConfiguration {

    @Bean
    public MongoClientOptions mongoOptions() {
         return MongoClientOptions.builder().maxConnectionIdleTime(6000 ).build();
    }
}

 

After passing the above settings, there is no Prematurely reached end of stream exception.

 

Spring boot trample log (@ springbootapplication conflicts with @ componentscan)

1. Introduction

Let’s take a look at the phenomenon. You can download the code here first

Let’s briefly introduce the classes inside

package com.iceberg.springboot.web;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
//@ComponentScan("com.iceberg.springboot.biz")
//@ComponentScan("com.iceberg.springboot.manager")
public class WebApplication {

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

Application startup class: I won’t say much about this. The above annotation is the key to this step

package com.iceberg.springboot.web.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
public class TestController implements ApplicationListener<ApplicationReadyEvent> {

    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        log.warn("--------------------------TestController had loaded-----------------------------");
    }
}

Testcontroller: applicationlistener is implemented here. When the spring container is started, this method will be called. Of course, the precondition is that testcontroller must be loaded into the spring container, so we can judge whether this class is loaded by spring through this log

As we all know, @ springbootapplication annotation will automatically scan the subpackages of the same package, so testcontroller will be loaded by spring

Let’s start the app and see the results

The log can be printed. It’s easy to understand. If it’s not printed, it’s the hell

Then we uncomment one of the @ componentscan and run it again

package com.iceberg.springboot.web;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@ComponentScan("com.iceberg.springboot.biz")
//@ComponentScan("com.iceberg.springboot.manager")
public class WebApplication {

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

The log is gone! What the fuck???

Don’t panic. Let’s open the second comment to see the result

package com.iceberg.springboot.web;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@ComponentScan("com.iceberg.springboot.biz")
@ComponentScan("com.iceberg.springboot.manager")
public class WebApplication {

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

The log appears again

I don’t know what’s your mood, but my mood is probably the same as that of the two expression packs above. I even suspected that spring had a bug, but in the end I found out the cause of the problem. As for whether it was a bug or not… You can judge for yourself

2、 Analysis of spring boot startup process

The complete process analysis can be seen here. We only analyze the parts used here, and directly look at reading @ componentscans

//ConfigurationClassParser.java
//Line 258
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
    //Omit part of the code
    
    Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
    
    //Omit part of the code
}

//AnnotationConfigUtils.java
//line 288
static Set<AnnotationAttributes> attributesForRepeatable(AnnotationMetadata metadata,
                                                         Class<?> containerClass, Class<?> annotationClass) {

    return attributesForRepeatable(metadata, containerClass.getName(), annotationClass.getName());
}

//AnnotationConfigUtils.java
//Line 295
//containerClassName:org.springframework.context.annotation.ComponentScans
//annotationClassName:org.springframework.context.annotation.ComponentScan
static Set<AnnotationAttributes> attributesForRepeatable(
    AnnotationMetadata metadata, String containerClassName, String annotationClassName) {

    Set<AnnotationAttributes> result = new LinkedHashSet<>();

    //find @ComponentScan
    addAttributesIfNotNull(result, metadata.getAnnotationAttributes(annotationClassName, false));

    //find @ComponentScans
    Map<String, Object> container = metadata.getAnnotationAttributes(containerClassName, false);
    if (container != null && container.containsKey("value")) {
        for (Map<String, Object> containedAttributes : (Map<String, Object>[]) container.get("value")) {
            addAttributesIfNotNull(result, containedAttributes);
        }
    }

    //Combine results
    return Collections.unmodifiableSet(result);
}

The upper part is the code of the overall process, and the problem part is the lower part. Let’s look at these two methods one by one

metadata.getAnnotationAttributes(annotationClassName, false))
metadata.getAnnotationAttributes(containerClassName, false)

Let’s look at the logic of metadata. Getannotationattributes (annotationclassname, false))

I’ve omitted the middle process. Anyway, if you go all the way down, you’ll get to the bottom

//AnnotatedElementUtils.java
//line 903
//element:class com.iceberg.springboot.web.WebApplication
//annotationName:org.springframework.context.annotation.ComponentScan
private static <T> T searchWithGetSemantics(AnnotatedElement element,
                                            Set<Class<?extends Annotation>> annotationTypes, @Nullable String annotationName,
                                            @Nullable Class<?extends Annotation> containerType, Processor<T> processor,
                                            Set<AnnotatedElement> visited, int metaDepth) {
    if (visited.add(element)) {
        try {
            //Get all annotations on the WebApplication class
            // This will fetch @SpringBootApplication and the unannotated @ComponentScan
            List<Annotation> declaredAnnotations = Arrays.asList(AnnotationUtils.getDeclaredAnnotations(element));
            T result = searchWithGetSemanticsInAnnotations(element, declaredAnnotations,
                                                           annotationTypes, annotationName, containerType, processor, visited, metaDepth);
            if (result != null) {
                return result;
            }

            //Omit part of the code
        }
        catch (Throwable ex) {
            AnnotationUtils.handleIntrospectionFailure(element, ex);
        }
    }

    return null;
}

The code at the top of

gets all the annotations on the application startup class, and then calls the searchWithGetSemanticsInAnnotations method to make the actual judgement. Here are three cases

Only @ springbootapplication annotation exists

There is @ springbootapplication and a @ componentscan annotation

There are @ springbootapplication and multiple @ componentscan annotations

Let’s analyze them one by one

(1) Only @ springbootapplication annotation exists

//AnnotatedElementUtils.java
//line 967
private static <T> T searchWithGetSemanticsInAnnotations(@Nullable AnnotatedElement element,
                                                         List<Annotation> annotations, Set<Class<?extends Annotation>> annotationTypes,
                                                         @Nullable String annotationName, @Nullable Class<?extends Annotation> containerType,
                                                         Processor<T> processor, Set<AnnotatedElement> visited, int metaDepth) {
    //The first for loop serves to detect the presence of the @ComponentScan annotation
    //Obviously there is no such annotation in the first case, so the code for the first loop is directly omitted
    
    //Omit part of the code
    
    //The second loop recursively looks for the presence of the @ComponentScan and @ComponentScans annotations in the annotation
    //This is where you find the @ComponentScan in @SpringBootApplication and return it
    //If you want to go deeper into how it works, you can look at the code yourself
    for (Annotation annotation : annotations) {
        Class<?extends Annotation> currentAnnotationType = annotation.annotationType();
        if (!AnnotationUtils.hasPlainJavaAnnotationsOnly(currentAnnotationType)) {
            T result = searchWithGetSemantics(currentAnnotationType, annotationTypes,
                                              annotationName, containerType, processor, visited, metaDepth + 1);
            if (result != null) {
                processor.postProcess(element, annotation, result);
                if (processor.aggregates() && metaDepth == 0) {
                    processor.getAggregatedResults().add(result);
                }
                else {
                    return result;
                }
            }
        }
    }
}

(2) There is @ springbootapplication and a @ componentscan annotation

//AnnotatedElementUtils.java
//line 967
private static <T> T searchWithGetSemanticsInAnnotations(@Nullable AnnotatedElement element,
                                                         List<Annotation> annotations, Set<Class<?extends Annotation>> annotationTypes,
                                                         @Nullable String annotationName, @Nullable Class<?extends Annotation> containerType,
                                                         Processor<T> processor, Set<AnnotatedElement> visited, int metaDepth) {
    for (Annotation annotation : annotations) {
        Class<?extends Annotation> currentAnnotationType = annotation.annotationType();
        if (!AnnotationUtils.isInJavaLangAnnotationPackage(currentAnnotationType)) {
            //Determine if the annotation is a @ComponentScan annotation
            if (annotationTypes.contains(currentAnnotationType) ||
                currentAnnotationType.getName().equals(annotationName) ||
                processor.alwaysProcesses()) {
                T result = processor.process(element, annotation, metaDepth);
                if (result ! = null) {
                    //we don't know what the function of this judgment is
                    //If you know, please tell us.
                    //but the judgment here is false, so the result will be returned directly
                    if (processor.aggregates() && metaDepth == 0) {
                        processor.getAggregatedResults().add(result);
                    }
                    else {
                        return result;
                    }
                }
            }
            
            //Omit part of the code
            
        }
    }
    
    //Omit the second loop
}

You can see that when there is a @ componentscan annotation, it will directly return this annotation, and will not parse the configuration in @ springbootapplication, so testcontroller is not loaded into the spring container

(3) There are @ springbootapplication and multiple @ componentscan annotations

If one @ componentscan annotation can override the corresponding configuration in @ springbootapplication, why can multiple @ componentscan annotations be used again

Haha, let’s first explain that the source code we analyzed before is under the spring core package, so even if you don’t use spring boot, its logic is the same. Then we usually use multiple @ componentscan without any problems

Here we will introduce a new annotation – @ repeatable. Let’s take a look at the code of @ componentscan

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
}

You can see that there is a @ repeatable annotation on the top. This is a new annotation added in jdk8. When there are multiple @ componentscan annotations, they will be converted into an array as the value of @ componentscans

So the third case is @ springbootapplication and a @ componentscans annotation. Note that there is s in this case, so the package scan in @ springbootapplication will still take effect

@The parsing logic of componentscans annotation is in the metadata. Getannotationattributes (containerclassname, false) method. The specific logic will not be analyzed. After all, we have found the root of the problem

3、 Summary

Then we summarize the reasons for the three phenomena

(1) Only @ springbootapplication can print the log normally

@Springbootapplication will scan the same package and sub package by default, so testcontroller will be scanned and the log will be printed

(2) There is @ springbootapplication and a @ componentscan annotation, and the log is not printed

@The componentscan annotation will be processed first and then returned so that the configuration in @ springbootapplication does not take effect

(3) There are @ springbootapplication and multiple @ componentscan annotations, and the log is printed normally

Multiple @ componentscan annotations will be integrated into one @ componentscan annotation, which will not affect the correct reading of the configuration in @ springbootapplication

Solution:

Use @ componentscan annotation instead of using @ componentscan annotation directly

This is the most perfect solution, which will not affect the configuration of springboot itself. You can also customize your own configuration at will

@SpringBootApplication
@ComponentScans({
        @ComponentScan("com.iceberg.springboot.biz"),
        @ComponentScan("com.iceberg.springboot.manager")  
})
public class WebApplication {

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

How to Solve Error: Failed to execute goal on project

Problem description

There is a mistake in the idea install module. After reading the console information, it is estimated that it is a dependency problem

[ERROR] Failed to execute goal on project 
xxx.yyy.share: Could not resolve dependencies for project 
com.dfl:xxx.yyy.zzz:jar:1.0-SNAPSHOT: 
Failure to find com.xxx:xxx-target:pom:1.0-SNAPSHOT in https://xxxx/snapshot 
was cached in the local repository, 
resolution will not be reattempted until the update interval of spring-snapshots has elapsed or updates are forced -> [Help 1]

Analysis and solution

From the log information, we can see that the zzz module can’t find the jar package, which comes from the target module and can’t be found in the local warehouse or private server.

It is speculated that the jar of private server warehouse is expired or deleted.

So I went to ask the boss, and sure enough, the jar of private server’s warehouse was deleted, so that the boss could deploy it again.