Spring Boot - 不是一个受管理的类型。

270

我使用Spring Boot + JPA,在启动服务时遇到了问题。

Caused by: java.lang.IllegalArgumentException: Not an managed type: class com.nervytech.dialer.domain.PhoneSettings
    at org.hibernate.jpa.internal.metamodel.MetamodelImpl.managedType(MetamodelImpl.java:219)
    at org.springframework.data.jpa.repository.support.JpaMetamodelEntityInformation.<init>(JpaMetamodelEntityInformation.java:68)
    at org.springframework.data.jpa.repository.support.JpaEntityInformationSupport.getMetadata(JpaEntityInformationSupport.java:65)
    at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getEntityInformation(JpaRepositoryFactory.java:145)
    at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:89)
    at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:69)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:177)
    at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.initAndReturn(RepositoryFactoryBeanSupport.java:239)
    at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:225)
    at org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean.afterPropertiesSet(JpaRepositoryFactoryBean.java:92)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1625)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1562)

以下是 Application.java 文件内容:

@Configuration
@ComponentScan
@EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class })
@SpringBootApplication
public class DialerApplication {

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

我使用UCp进行连接池,并且以下是数据源的配置:

@Configuration
@ComponentScan
@EnableTransactionManagement
@EnableAutoConfiguration
@EnableJpaRepositories(entityManagerFactoryRef = "dialerEntityManagerFactory", transactionManagerRef = "dialerTransactionManager", basePackages = { "com.nervy.dialer.spring.jpa.repository" })
public class ApplicationDataSource {

    /** The Constant LOGGER. */
    private static final Logger LOGGER = LoggerFactory
            .getLogger(ApplicationDataSource.class);

    /** The Constant TEST_SQL. */
    private static final String TEST_SQL = "select 1 from dual";

    /** The pooled data source. */
    private PoolDataSource pooledDataSource;

用户详细信息服务实现,

@Service("userDetailsService")
@SessionAttributes("user")
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UserService userService;

服务层实现,

@Service
public class PhoneSettingsServiceImpl implements PhoneSettingsService {

}

仓库类,

@Repository
public interface PhoneSettingsRepository extends JpaRepository<PhoneSettings, Long> {

}

实体类,

@Entity
@Table(name = "phone_settings", catalog = "dialer")
public class PhoneSettings implements java.io.Serializable {

WebSecurityConfig类,

@Configuration
@EnableWebMvcSecurity
@ComponentScan
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    /**
     * Instantiates a new web security config.
     */
    public WebSecurityConfig() {

        super();
    }

    /**
     * {@inheritDoc}
     * @see org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#configure(org.springframework.security.config.annotation.web.builders.HttpSecurity)
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.authorizeRequests()
            .antMatchers("/login", "/logoffUser", "/sessionExpired", "/error", "/unauth", "/redirect", "*support*").permitAll()
            .anyRequest().authenticated().and().rememberMe().and().httpBasic()
            .and()
            .csrf()
            .disable().logout().deleteCookies("JSESSIONID").logoutSuccessUrl("/logoff").invalidateHttpSession(true);
    }


    @Autowired
    public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {

      auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
    }

}

以下是包的分类:

  1. Application 类位于 - com.nervy.dialer
  2. Datasource 类位于 - com.nervy.dialer.common
  3. 实体类位于 - com.nervy.dialer.domain
  4. 服务类位于 - com.nervy.dialer.domain.service.impl
  5. 控制器位于 - com.nervy.dialer.spring.controller
  6. 仓库类位于 - com.nervy.dialer.spring.jpa.repository
  7. WebSecurityConfig 位于 - com.nervy.dialer.spring.security

谢谢!


1
我相信你仍然需要告诉Hibernate扫描包以寻找你的实体对象。 - chrylis -cautiouslyoptimistic-
33个回答

2

当我从Spring Boot 1.3.x迁移到1.5时,遇到了一些问题,但在更新EntityManagerFactory bean中的entity包后已经解决。

  @Bean(name="entityManagerFactoryDef")
  @Primary
  public LocalContainerEntityManagerFactoryBean defaultEntityManager() {
      Map map = new HashMap();
      map.put("hibernate.default_schema", env.getProperty("spring.datasource.username"));
      map.put("hibernate.hbm2ddl.auto", env.getProperty("spring.jpa.hibernate.ddl-auto"));
      LocalContainerEntityManagerFactoryBean em = createEntityManagerFactoryBuilder(jpaVendorProperties())
              .dataSource(primaryDataSource()).persistenceUnit("default").properties(map).build();
      em.setPackagesToScan("com.simple.entity");
      em.afterPropertiesSet();
      return em;
  }

这个Bean在Application类中被引用,如下所示:

@SpringBootApplication
@EnableJpaRepositories(entityManagerFactoryRef = "entityManagerFactoryDef")
public class SimpleApp {

}

2

根据我的经验,您应该检查您的注释。如果您将其用作bean,则必须使用@Component。但是作为存储库中的实体,则应在类上方使用@Entity


1
我遇到了类似的问题。在我的情况下,仓库和被管理的类型不在同一个包中。

它们不需要在同一个包中。事实上,它们不应该在同一个包中。 - Toni Nagy
标记为不是答案。这并没有帮助解决问题,只是表达“同样的问题”(不是答案)。 - hc_dev

0
如果您正在使用SessionFactory作为EMF:
在我的情况下,问题是我忘记在Hibernate配置中将新实体类型(导致错误)作为注释类包含在内。
因此,在您的SessionFactory bean中,请不要忘记为新实体类型包括以下行:
configuration.addAnnotatedClass(MyEntity.class);

0

你可以检查Java版本,我在更改版本后解决了我的问题。

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.1</version>
    <relativePath />
</parent>

1
spring-boot-starter-parent 的父版本和版本号与 "Java 版本" 有什么关系?是否存在兼容性问题?请解释。 - hc_dev

0

以下方法对我有效...

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import org.apache.catalina.security.SecurityConfig;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

import com.something.configuration.SomethingConfig;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = { SomethingConfig.class, SecurityConfig.class }) //All your configuration classes
@EnableAutoConfiguration
@WebAppConfiguration // for MVC configuration
@EnableJpaRepositories("com.something.persistence.dataaccess")  //JPA repositories
@EntityScan("com.something.domain.entity.*")  //JPA entities
@ComponentScan("com.something.persistence.fixture") //any component classes you have
public class SomethingApplicationTest {

    @Autowired
    private WebApplicationContext ctx;
    private MockMvc mockMvc;

    @Before
    public void setUp() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(ctx).build();
    }

    @Test
    public void loginTest() throws Exception {
        this.mockMvc.perform(get("/something/login"))
        .andDo(print()).andExpect(status().isOk());
    }

}

0

我通过在appliation.properties文件中添加以下内容解决了这个问题。

spring.jpa.packagesToScan= 您的实体文件夹路径,例如com.java.entity


0

如果你正在使用多模块Spring Data JPA项目,以下内容可能适用于你。

如果你正在使用多个模块,并且它们具有Jpa实体和存储库,则可能会发生这种情况。我曾经在外部Tomcat上部署时遇到“不是受管理的类型”错误(从未在嵌入式Tomcat中遇到过)。

我有1个主模块和2个其他模块作为依赖项。当将主项目部署为WAR文件时,我可以看到总共有3个Spring应用程序正在初始化。当执行顺序是首先执行主模块,然后执行子模块时,就不会出错。但有时,子模块会在主模块之前被调用。这会导致“不是受管理的类型实体异常”

棘手的问题是,在Spring Boot嵌入式Tomcat中不会显示错误。但是,当我们将其部署在外部Tomcat中时,此异常会随机出现。我不得不多次部署相同的WAR文件才能获取正确的顺序。

我花了一整天的时间来解决这个问题。但结果是,问题出在我在主模块中添加其他模块作为依赖的方式上。如果您正在将Spring Boot模块作为另一个项目的依赖项添加,请确保主类不参与jar包。当您将另一个Spring Boot项目作为依赖项,并尝试将该项目部署为war时,主应用程序类的执行顺序不能保证。删除主类将基本上避免子模块的独立执行。因此,就不会有任何执行顺序问题的余地了。

0

我认为没有人提到过,但值得注意的是,Not a managed type错误也可能是由于软件包字母大小写造成的。 例如,如果要扫描的软件包名为myEntities,而我们在软件包扫描配置中提供了myentities,那么它在一台机器上可能会工作,而在另一台机器上则不会,因此要小心字母大小写。


0

我有同样的问题,在Spring Boot版本v1.3.x中,我所做的是将Spring Boot升级到版本1.5.7.RELEASE。然后问题就解决了。


1
我之前使用的是1.3.x版本,然后切换到了1.5.6版本,出现了问题。 - apkisbossin
这个“相同的问题”陈述是一个很好的评论,但不是一个答案。请将其移动到问题的评论中。 - hc_dev
请提供一些链接或解释,说明为什么迁移到版本 1.5.7 可以解决这个问题。 - hc_dev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接