springBoot框架shedlock+websocket功能冲突的解决方案

背景描述:

项目开发中首先遇到在集群模式部署服务端时,多个节点的定时任务在各自的节点处均会执行一遍的问题,针对这个单一问题,上一篇文章https://www.cnblogs.com/Iris1998/p/11413099.html给出了springboot集成shedlock的解决方案,但一段时间后项目中有了新的需求,想要实现消息主动推到客户端的功能,单从功能上来看可以采用springboot自带的websocket实现,但开发过程遇到很奇怪的报错,报错信息如下
{"time":"2019-09-27 11:07:22 626", "level":"WARN", "classname":"org.apache.juli.logging.DirectJDKLog", "method":"log", "line":"173", "msg":"The web application [ROOT] appears to have started a thread named [RxIoScheduler-1 (Evictor)] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
 sun.misc.Unsafe.park(Native Method)
 java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
 java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)
 java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1093)
 java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
 java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
 java.lang.Thread.run(Thread.java:748)"}
{"time":"2019-09-27 11:07:22 666", "level":"ERROR", "classname":"org.springframework.boot.SpringApplication", "method":"reportFailure", "line":"858", "msg":"Application run failed"}
org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘stompWebSocketHandlerMapping‘ defined in class path resource [org/springframework/web/socket/config/annotation/DelegatingWebSocketMessageBrokerConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.web.servlet.HandlerMapping]: Factory method ‘stompWebSocketHandlerMapping‘ threw exception; nested exception is java.lang.IllegalStateException: @Bean method AbstractMessageBrokerConfiguration.messageBrokerTaskScheduler called as bean reference for type [org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler] but overridden by non-compatible bean instance of type [com.sun.proxy.$Proxy220]. Overriding bean of same name declared in: class path resource [org/springframework/web/socket/config/annotation/DelegatingWebSocketMessageBrokerConfiguration.class]
	at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:627)
	at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:456)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1288)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1127)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:538)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:498)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:846)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:863)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:546)
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:142)
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775)
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:316)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248)
	at com.hundunyun.wechat.App.main(App.java:19)
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.web.servlet.HandlerMapping]: Factory method ‘stompWebSocketHandlerMapping‘ threw exception; nested exception is java.lang.IllegalStateException: @Bean method AbstractMessageBrokerConfiguration.messageBrokerTaskScheduler called as bean reference for type [org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler] but overridden by non-compatible bean instance of type [com.sun.proxy.$Proxy220]. Overriding bean of same name declared in: class path resource [org/springframework/web/socket/config/annotation/DelegatingWebSocketMessageBrokerConfiguration.class]
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185)
	at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:622)
	... 19 common frames omitted
Caused by: java.lang.IllegalStateException: @Bean method AbstractMessageBrokerConfiguration.messageBrokerTaskScheduler called as bean reference for type [org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler] but overridden by non-compatible bean instance of type [com.sun.proxy.$Proxy220]. Overriding bean of same name declared in: class path resource [org/springframework/web/socket/config/annotation/DelegatingWebSocketMessageBrokerConfiguration.class]
	at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.resolveBeanReference(ConfigurationClassEnhancer.java:418)
	at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:366)
	at org.springframework.web.socket.config.annotation.DelegatingWebSocketMessageBrokerConfiguration$$EnhancerBySpringCGLIB$$748fbfa6.messageBrokerTaskScheduler(<generated>)
	at org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurationSupport.stompWebSocketHandlerMapping(WebSocketMessageBrokerConfigurationSupport.java:76)
	at org.springframework.web.socket.config.annotation.DelegatingWebSocketMessageBrokerConfiguration$$EnhancerBySpringCGLIB$$748fbfa6.CGLIB$stompWebSocketHandlerMapping$14(<generated>)
	at org.springframework.web.socket.config.annotation.DelegatingWebSocketMessageBrokerConfiguration$$EnhancerBySpringCGLIB$$748fbfa6$$FastClassBySpringCGLIB$$19a6d0cf.invoke(<generated>)
	at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244)
	at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:363)
	at org.springframework.web.socket.config.annotation.DelegatingWebSocketMessageBrokerConfiguration$$EnhancerBySpringCGLIB$$748fbfa6.stompWebSocketHandlerMapping(<generated>)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
	... 20 common frames omitted

 经过实验,独自使用shedlock没有问题,独自使用websocket也没有问题,但两个放在一起就有问题,大胆猜测问题出在springBoot的shedlock和websocket的底层,尝试解决无果后决定换一种实现方式,springboot的websocket+redis分布式锁实现分布式环境中两个功能的兼容。

第一步:引入相关包

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
            <version>2.2.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>            <version>2.2.1</version>         </dependency>
        <!--测试依赖项-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- 负载均衡定时任务执行一次 -->
        <dependency>
            <groupId>net.javacrumbs.shedlock</groupId>
            <artifactId>shedlock-spring</artifactId>
            <version>2.2.1</version>
        </dependency>
        <dependency>
            <groupId>net.javacrumbs.shedlock</groupId>
            <artifactId>shedlock-provider-redis-jedis</artifactId>
            <version>2.2.1</version>
        </dependency>     <dependency>       <groupId>com.alibaba</groupId>        <artifactId>fastjson</artifactId>        <version>1.2.41</version>     </dependency>

第二步:添加redis分布式锁功能相关的文件

1.添加自定义锁注解

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CacheLock {
    String lockedPrefix() default "";   //redis 锁key的前缀
    int expireTime() default 10;      //key在redis里存在的时间,1000S
}

2.添加aop切面类

import com.iris.websocket.annotation.CacheLock;
import com.iris.websocket.springwebsocket.redis.RedisClient;
import lombok.Synchronized;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/*
 * @Description TODO
 * @Author muruan.lt
 * @Date 2019/9/26 11:36
 */
@Aspect
@Slf4j
@Component
public class CacheLockAspect {
    private static final String LOCK_VALUE = "locked";

    @Autowired
    RedisClient redisClient;

    /*
     * 1.有springboot-websocket情况下不用@Synchronized这个注解,可能多线程导致的分布式锁不生效
     * 2.没有springboot-websocket情况下可以不用@Synchronized这个注解
     */
    @Around("@annotation(com.iris.websocket.annotation.CacheLock)")
    @Synchronized
    public void cacheLockPoint(ProceedingJoinPoint pjp) {

        String name = pjp.getSignature().getName();
        Method[] methods = pjp.getTarget().getClass().getMethods();
        for (Method cacheMethod : methods) {
            if (null != cacheMethod.getAnnotation(CacheLock.class)
                    && name.equals(cacheMethod.getName())){
                try {
//                    String lockKey = pjp.getTarget().getClass().getName()+cacheMethod.getAnnotation(CacheLock.class).lockedPrefix();
                    String lockKey = cacheMethod.getAnnotation(CacheLock.class).lockedPrefix();
                    int timeOut = cacheMethod.getAnnotation(CacheLock.class).expireTime();
                    if(null == lockKey){
                        return;
                    }
                    if (redisClient.setnx(lockKey, LOCK_VALUE)) {
                        redisClient.expire(lockKey, timeOut);
//                        log.info("method:{}获取锁:{},开始运行!",cacheMethod,lockKey);
                        pjp.proceed();
                        return;
                    }
//                    log.info("method:{}未获取锁:{},运行失败!",cacheMethod,lockKey);
                } catch (Throwable e) {
                    log.error("method:{},运行错误!",cacheMethod,e);
                    return;
                }
                break;
            }
        }
    }
}

3.添加application.properties配置文件

server.port: 8800
spring.application.name: sun-websocket

eureka.instance.hostname: localhost
eureka.client.registerWithEureka: false
eureka.client.fetchRegistry: false
serviceUrl.defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

####################################### redis 配置信息开始 ###########################################
redis.host=127.0.0.1
redis.password=123456
redis.port=6379
#最大能够保持idel状态的对象数
redis.maxIdle=300
#最大分配的对象数
redis.maxActive=600
#当池内没有返回对象时,最大等待时间
redis.maxWaitMillis=1000
redis.maxTotal=1000
#当调用borrow Object方法时,是否进行有效性检查
redis.testOnBorrow=true
#当调用return Object方法时,是否进行有效性检查
redis.testOnReturn=true
redis.timeout=3600
####################################### redis 配置信息结束 ###########################################

4.添加redis配置相关文件

4.1 添加 RedisPool.java 文件

import org.springframework.beans.factory.annotation.Value;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/*
* @Description:    JedisPool配置类,配置信息在默认的"application.properties"文件中
* @Author:         muruan.lt
* @CreateDate:     2019/9/27 9:50
* @Version:        1.0
*/
public abstract class RedisPool {

    public JedisPool jedisPool;

    @Value("${redis.host}")
    private String host;
    @Value("${redis.port}")
    private Integer port;
    @Value("${redis.password}")
    private String password;
    @Value("${redis.maxIdle}")
    private Integer maxIdle;
    @Value("${redis.maxTotal}")
    private Integer maxTotal;
    @Value("${redis.maxActive}")
    private Integer maxActive;
    @Value("${redis.maxWaitMillis}")
    private Integer maxWaitMillis;
    @Value("${redis.timeout}")
    private Integer timeout;
    @Value("${redis.testOnBorrow}")
    private Boolean testOnBorrow;
    @Value("${redis.testOnReturn}")
    private Boolean testOnReturn;

    protected RedisPool() {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxIdle(maxIdle);
        jedisPoolConfig.setMaxTotal(maxTotal);
        jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
        jedisPoolConfig.setTestOnBorrow(testOnBorrow);
        jedisPoolConfig.setTestOnReturn(testOnReturn);
        jedisPool =
                new JedisPool(jedisPoolConfig, host, port, timeout, password);
    }
}

4.2 添加 RedisClient.java 文件

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.*;
import redis.clients.jedis.exceptions.JedisConnectionException;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

@Component
public class RedisClient {
    private static final Logger loggger = LoggerFactory.getLogger(RedisClient.class);

    @Autowired
    private JedisPool jedisPool;

    private Jedis getJedis() {
        Jedis jedis = jedisPool.getResource();
//        jedis.select(database);
        return jedis;
    }

    public void set(String key, String value) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            jedis.set(key, value);
        } finally {
            jedis.close();
        }
    }

    public void set(String key, String value, int expTime) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            jedis.setex(key, expTime, value);
        } finally {
            jedis.close();
        }
    }

    public String get(String key) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.get(key);
        } finally {
            jedis.close();
        }
    }

    public void expire(String key, int expTime) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            jedis.expire(key, expTime);
        } finally {
            jedis.close();
        }
    }

    public boolean setnx(String lockKey, String expires) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            Long result = jedis.setnx(lockKey, expires);
            return result == 1;
        } finally {
            jedis.close();
        }
    }
}

4.3 添加RedisConfig.java文件

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import redis.clients.jedis.JedisPool;

import java.lang.reflect.Method;

/*
 * @Description 服务于shedlock-redis
 * @Author muruan.lt
 * @Date 2019/9/26 10:19
 */
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {

    @Value("${redis.host}")
    private String host;
    @Value("${redis.port}")
    private Integer port;

    @Bean
    @Override
    public KeyGenerator keyGenerator() {
        return new KeyGenerator() {
            @Override
            public Object generate(Object target, Method method, Object... params) {
                StringBuilder sb = new StringBuilder();
                sb.append(target.getClass().getName());
                sb.append(method.getName());
                for (Object o : params) {
                    if (o != null) {
                        sb.append(o.toString());
                    }
                }
                return sb.toString();
            }
        };
    }

    @Bean
    public RedisTemplate<String, String> myRedisTemplate(RedisConnectionFactory factory) {
        StringRedisTemplate srt = new StringRedisTemplate(factory);
        Jackson2JsonRedisSerializer j2j = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        j2j.setObjectMapper(om);
        srt.setValueSerializer(j2j);
        srt.afterPropertiesSet();
        return srt;
    }

    @Bean
    public JedisPool jedisPool() {
        return new JedisPool(this.host, this.port);
    }
}

以上就完成了所有redis分布式锁功能相关的文件添加,下面就是websocket需要添加的文件

第三步:添加websocket功能相关的文件

1. 添加websocket配置文件

import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;

/*
 * @Description springWebsoket配置文件
 * @Author muruan.lt
 * @Date 2019/9/24 09:23
 */
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/topic");
        config.setApplicationDestinationPrefixes("/app");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/websocket").setAllowedOrigins("*").withSockJS();
    }
}

至此就完成了两个功能相关的全部文件,下面就是功能的使用和检测。

第四步:功能的使用和检测

import com.alibaba.fastjson.JSONObject;
import com.iris.websocket.annotation.CacheLock;
import lombok.extern.slf4j.Slf4j;
import net.javacrumbs.shedlock.core.SchedulerLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.simp.SimpMessageSendingOperations;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.Date;

/*
 * @Description 定时任务测试类
 * @Author muruan.lt
 * @Date 2019/9/2 14:27
 */
@Component
@Slf4j
public class TaskTest {

    @Autowired
    private SimpMessageSendingOperations messageTemplate;

    @Scheduled(cron = "0/10 * * * * ?")
    @CacheLock(lockedPrefix = "test",expireTime=9)
    public void test1(){
        System.out.println(new Date() + "hello1!");
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("code", 200);
        jsonObject.put("content", "hello1!");
        String resStr = jsonObject.toJSONString();
        log.info("send message to browser,message content [{}]", resStr);
        messageTemplate.convertAndSend("/topic/greetings", resStr);
    }

    @Scheduled(cron = "0/10 * * * * ?")
    @CacheLock(lockedPrefix = "test",expireTime=9)
    public void test2(){
        System.out.println(new Date() + "hello2!");
    }

    /**
     * 执行定时任务
     **/
    @Scheduled(cron = "0/10 * * * * ?")
    @CacheLock(lockedPrefix = "TimeTaskService",expireTime=9)
    public void executeTask() {
        System.out.println(new Date() +"hello3!");
    }

    /**
     * 执行定时任务
     **/
    @Scheduled(cron = "0/10 * * * * ?")
    @CacheLock(lockedPrefix = "TimeTaskService",expireTime=9)
    public void executeTask1() {
        System.out.println(new Date() +"hello4!");
    }
}

websocket的使用:在需要向前端推送消息的地方添加

@Autowired
private SimpMessageSendingOperations messageTemplate;

即可,向特定的topic发送相关,客户端就可以通过这个topic接收到新消息

@CacheLock(lockedPrefix = "TimeTaskService",expireTime=9)

这个注解就是实现分布式redis锁的关键,在需要解决分布式部署重复执行问题的方法上添加此注解就可以解决分布式部署重复执行的问题。

原文地址:https://www.cnblogs.com/Iris1998/p/11599517.html

时间: 2024-11-09 21:54:22

springBoot框架shedlock+websocket功能冲突的解决方案的相关文章

spring-boot框架下的websocket服务

这几天在做web端实时展示服务端日志文件新增内容的功能.要满足实时的需求,我选择的方案是在web端跟服务端建立一个websocket链接,由服务端通过tail -f 命令将文件新增内容发送给web端. 关于websocket的介绍,可以参考这篇博文:http://www.cnblogs.com/lizhenghn/p/5155933.html(链接仅用于学习交流,如有版权问题请及时告知).这里我主要想介绍的是在spring-boot框架下如何发布websocket服务. 一.在服务端发布webs

【转】【译】JavaScript魔法揭秘--探索当前流行框架中部分功能的处理机制

推荐语: 今天推荐一篇华为同事的同事翻译的一篇文章,推荐的主要原因是作为一个华为员工居然晚上还能写文章,由不得小钗不佩服!!! 其中的jQuery.angular.react皆是十分优秀的框架,各有特点,各位可以看看 编辑:github 原文链接:Revealing the Magic of JavaScript jnotnull发布在 JavaScript译文 我们每天都在使用大量的工具,不同的库和框架已经成为我们日常工作的一部分.我们使用他们是因为我们不想重新造轮子,虽然我们可能并不知道这些

Springboot框架了解与搭建(1)

在上一章,我讲解了React+node+express相应的框架搭建,一个项目只有一个前端框架够么,当然不够啦!!! 所以这节我们就来讲后台springboot框架的搭建和相关原理吧~~~版本(2.1.0) 1.搭建Springboot所需要的前提 ①JDK8 或 JDK9 ②Maven3.2+ 或 Gradle4.0+版本(我的随笔内用的都是Maven) 2. 到底什么是Springboot么,让我们来看下图 意思就是: Springboot是Spring框架的集成,相比Spring框架, 除

springboot 框架 - helloword

功能:浏览器发送hello请求,服务器接收请求并处理,返回hello word字符串 一.创建一个maven项目 二.在pom.xml文件中添加依赖导入springboot框架运行需要的依赖 1 <!-- 继承了一个父项目 --> 2 <parent> 3 <groupId>org.springframework.boot</groupId> 4 <artifactId>spring-boot-starter-parent</artifac

springboot框架,文件上传问题===org.springframework.web.HttpMediaTypeNotSupportedException: Content type &#39;multipart/form-data;

使用IDEA开发springboot项目,需求中要提交数据项和文件上传,同时接收实体bean对象和文件,后台Controller接收配置方式: Controller代码如下: 1 @RequestMapping(value="/comment",method = RequestMethod.POST) 2 public @ResponseBody RetResult saveIndustryComment(HttpServletRequest request,@RequestParam

关于eclipse复制当前行快捷键与笔记本屏幕旋转快捷键冲突的解决方案

eclipse中复制当前行快捷键是Ctrl+Alt+↑或者Ctrl+Alt+↓但是在某些笔记本上使用此快捷键效果却是屏幕上下旋转有一种可能是你的笔记本上安装了intel的显卡芯片驱动方法一:此驱动有一个控制面板,其中有一个全局快捷键设置,把快捷键修改成其他的或者直接关闭就可以解决冲突.方法二:当然,也可以修改eclipse的快捷键.方法一步骤如下: 关于eclipse复制当前行快捷键与笔记本屏幕旋转快捷键冲突的解决方案,布布扣,bubuko.com

考试系统--底层框架发布时遇到的问题解决方案(Window7 IIS6.0)(三)

<承接上篇文章> 考试系统--底层框架发布时遇到的问题解决方案(Window7 IIS6.0)(二) 4.问题描述 内存入口检查失败,因为可用没存(XX字节)少于总内存的XX%,因此,该服务不可用于传入的请求.若要解决此问题,请减少计算机上的负载,或调整serviceHostingEnvironment配置元素上的minFreeMemoryPercentageToActivateService的值. 解决方法:服务是运行在电脑上的应用程序,并且服务执行耗费资源的操作,因此有必要确保其在开始运行

继续封装jQuery框架的模块功能

在前两天已经封装了框架的选择器模块的函数了,在这里为了保持代码的完整性,以及体现框架模块的功能.这里用一个h5的方法,简单表示选择器模块. 1 (function(window){ //传入window全局对象,可以减少作用域的访问深度 2 //1.选择器模块 3 var select = (function () { 4 return function (selector, context) { 5 if (context) { 6 return context.querySelectorAl

php中并发读写文件冲突的解决方案(文件锁应用示例)

PHP(外文名: Hypertext Preprocessor,中文名:“超文本预处理器”)是一种通用开源脚本语言.语法吸收了C语言.Java和Perl的特点,入门门槛较低,易于学习,使用广泛,主要适用于Web开发领域.PHP的文件后缀名为php. 本文为大家讲解的是php中并发读写文件冲突的解决方案(文件锁应用示例),感兴趣的同学参考下. 在这里提供4种高并发读写文件的方案,各有优点,可以根据自己的情况解决php并发读写文件冲突的问题. 对于日IP不高或者说并发数不是很大的应用,一般不用考虑这