求助,spring-boot升级带来的异常

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了求助,spring-boot升级带来的异常相关的知识,希望对你有一定的参考价值。

参考技术A 在开发Spring Boot应用的过程中,Spring Boot直接执行public static void main()函数并启动一个内嵌的应用服务器(取决于类路径上的以来是Tomcat还是jetty)来处理应用请求。对于生产环境,这样的部署方式同样有效,同时Spring Boot也支持传统的部署方式——将war包放入应用服务器中启动运行。 内嵌应用服务器 在使用Maven或Gradle构建Spring Boot应用的过程中,Spring Boot插件提供了巨大的帮助,除了生命各类预定义的依赖,它还能够构建可以直接运行的jar包——包含了所有的依赖以及内嵌应用服务器。应用的分发也就变得非常简单,任何人拿到了这个jar包,只需要简单运行java -jar your.jar就可以启动应用,无需任何构建工具、安装过程以及应用服务器。 内嵌应用服务器配置 在生产环境中,应用服务器需要各类配置,Spring Boot本身提供了一种非常简单的配置机制——application.properties: server.port=8080 # 监听端口 server.address= # 绑定的地址 server.session-timeout= #session有效时长 server.context-path= #默认为/ server.ssl.* #ssl相关配置 Tomcat 默认情况下,Spring Boot启动的内嵌容器就是Tomcat,对于Tomcat有几个非常重要的配置: server.tomcat.basedir=/tmp tomcat的baseDir,日志、dump等文件都存在于这个目录中,一般是系统的临时文件夹/tmp,但也可以按照自己的需求变更位置。 server.tomcat.access-log-pattern= # log pattern of the access log server.tomcat.access-log-enabled=false # is access logging enabled 这两个配置打开Tomcat的Access日志,并可以设置日志格式。 Jetty 如果你不喜欢Tomcat,Jetty也是一个非常不错的选择。使用Jetty的方式也非常简单——把tomcat依赖从Maven或Gradle中移除,加入Jetty内嵌容器的依赖: org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-tomcat org.springframework.boot spring-boot-starter-jetty Java EE应用服务器 除了内嵌容器的部署模式,Spring Boot也支持将应用部署至已有的Tomcat容器, 或JBoss, WebLogic等传统Java EE应用服务器。 以Maven为例,首先需要将从jar改成war,然后取消spring-boot-maven-plugin,然后修改Application.java: package demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.context.web.SpringBootServletInitializer; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @Configuration @ComponentScan @EnableAutoConfiguration public class Application extends SpringBootServletInitializer public static void main(String[] args) SpringApplication.run(applicationClass, args); @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) return application.sources(applicationClass); private static Class applicationClass = Application.class; 接下来打包应用,将生成的war包放入应用服务器目录即可。 使用外部配置文件 在应用程序中有很多配置项,例如数据库连接地址、日志文件位置、应用服务器配置等等。为了安全与灵活性,我们推荐将Spring Boot的配置文件放在生产环境的服务器上,并严格控制访问权限。在运行应用时可以通过命令行参数指定配置文件: java -jar location_of_your_jar_file.jar --spring.config.location=location_of_your_config_file.properties 这样做的好处是: 配置位于生产环境中,数据库连接等私密信息不容易泄露 灵活性强,同一份代码(包括构建的jar包)可以应用于不同的环境配置(开发、测试、生产) 使用Profile区分环境 在某些情况下,应用的某些业务逻辑可能需要有不同的实现。例如邮件服务,假设EmailService中包含的send(String email)方法向指定地址发送电子邮件,但是我们仅仅希望在生产环境中才执行真正发送邮件的代码,而开发环境里则不发送以免向用户发送无意义的垃圾邮件。 我们可以借助Spring的注解@Profile实现这样的功能,这样需要定义两个实现EmailService借口的类: @Service @Profile("dev") class DevEmailService implements EmailService public void send(String email) //Do Nothing @Service @Profile("prod") class ProdEmailService implements EmailService public void send(String email) //Real Email Service Logic @Profile("dev")表明只有Spring定义的Profile为dev时才会实例化DevEmailService这个类。那么如何设置Profile呢? 在配置文件中指定 在application.properties中加入: spring.profiles.active=dev 通过命令行参数 java -jar app.jar --spring.profiles.active=dev 以服务的形式运行应用 使用java命令运行应用非常简单,但是通常我们都是通过ssh命令连接到服务器并运行它,一旦ssh连接断开,那么由它fork的java子进程也就随之销毁了。所以我们必须借助工具将应用作为服务运行在服务器上: Systemd systemd 是Linux 下的一款系统和服务管理器。可以为Spring Boot应用编写启动脚本: [Unit] Description=Spring Boot Application [Service] ExecStart=/usr/bin/java -jar location_of_jar_file.jar --spring.config.location=location_of_config.properties --spring.profiles.active=profile User=$your expected user [Install] WantedBy=multi-user.target Supervisord Supervisord是用Python实现的一款非常实用的进程管理工具。可以为Spring Boot应用编写: [program:app] 中国mand=/usr/bin/java -jar location_of_jar_file.jar --spring.config.location=location_of_config.properties --spring.profiles.active=profile user=$your expected user autostart=true autorestart=true startsecs=10 startretries=

Spring-boot,无法自动装配类。未找到默认构造函数引发异常

【中文标题】Spring-boot,无法自动装配类。未找到默认构造函数引发异常【英文标题】:Spring-boot, unable to autowire a class.No default constructor found Exception is raised 【发布时间】:2013-12-24 22:41:46 【问题描述】:

我是弹簧靴的新手。在我将一个类移动到不同的包(另一个包含“应用程序”)后,无法实例化 bean 类:未找到默认构造函数引发异常。

之前(可行的代码)

package com.server;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Controller;

@Configuration
@ComponentScan(basePackages = "com.server" )
@EnableAutoConfiguration
@Profile( "default" )
@Controller
public class Application  

    private static Log logger = LogFactory.getLog(Application.class);

    public static void main(String[] args) 
        logger.info("Starting Application...");
        SpringApplication.run(Application.class, args);
    


来自http://bitwiseor.com/2013/09/20/creating-test-services-with-spring-boot/的一段代码

package com.server;

import java.util.Collections;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Configuration
@Controller
@Profile( "default" )
class Franchise 

    private JdbcTemplate jdbcTemplate;

    @Autowired
    public Franchise(DataSource dataSource) 
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    

    @ResponseBody
    @RequestMapping("/api/franchise/id")
    String franchiseId(@PathVariable Long id) 
        try 
            return jdbcTemplate.queryForMap("SELECT id, title FROM franchises WHERE id=?", id).toString();
         catch(EmptyResultDataAccessException ex) 
            return Collections.EMPTY_MAP.toString();
        
    

    @ResponseBody
    @RequestMapping("/api/franchise")
    String franchises() 
        try 
            return jdbcTemplate.queryForList("SELECT id, title FROM franchises").toString();
         catch(EmptyResultDataAccessException ex) 
            return Collections.EMPTY_MAP.toString();
        
    

当“Application”类和“Franchise”类位于同一个包中时,我可以启动服务器。但是,当我将类“特许经营”移动到另一个包中时,如下所示,我遇到了这个异常:无法实例化 bean 类:未找到默认构造函数引发异常。

package com.server.api;

import java.util.Collections;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Configuration
@Controller
@Profile( "default" )
class Franchise 

    private JdbcTemplate jdbcTemplate;

    @Autowired
    public Franchise(DataSource dataSource) 
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    

    @ResponseBody
    @RequestMapping("/api/franchise/id")
    String franchiseId(@PathVariable Long id) 
        try 
            return jdbcTemplate.queryForMap("SELECT id, title FROM franchises WHERE id=?", id).toString();
         catch(EmptyResultDataAccessException ex) 
            return Collections.EMPTY_MAP.toString();
        
    

    @ResponseBody
    @RequestMapping("/api/franchise")
    String franchises() 
        try 
            return jdbcTemplate.queryForList("SELECT id, title FROM franchises").toString();
         catch(EmptyResultDataAccessException ex) 
            return Collections.EMPTY_MAP.toString();
        
    

如果我想将这个类移到不同的包中,我该如何解决这个问题?

谢谢!


编辑:我找到了解决方案 当我删除以下标签时,我可以将类放入单独的包中。 @配置 @Profile( "默认" )

但我不知道为什么......

【问题讨论】:

@Configuration 需要一个代理,准确地说是一个 cglib 代理,这反过来又需要一个类有一个默认的构造函数。你的@Controller 不应该是@Configuration(恕我直言,这违反了单一责任规则)。你的 Application 类也是如此,它不是一个控制器,所以为什么它有一个 @Controller 注释。另请注意,@Profile("default") 是多余的,因为这是默认设置。 @M.Deinum 感谢您的解释! 【参考方案1】:

在我看来,您的 Franchise 类是包私有的(java 类的默认可见性)。这将解释一切(不需要涉及 Spring 或编译器以外的任何东西)。要修复它,只需将您的类声明为“public”。

Marten 也是正确的,@Configuration 可能不希望您对特许经营权意味着什么(但在这种情况下它是无害的)。

【讨论】:

非常感谢您的解释!~

以上是关于求助,spring-boot升级带来的异常的主要内容,如果未能解决你的问题,请参考以下文章

python升级带来的yum异常:File "/usr/bin/yum", line 30

python升级带来的yum异常(解决错误File "/usr/bin/yum", line 30 except KeyboardInterrupt, e:)

具有 Liquibase 重载属性的 Spring-boot

测试开发专题:spring-boot自定义异常返回

测试开发专题:spring-boot自定义异常返回

无法访问系统带来的一个思考