Spring Data - Service类中的@Transactional注释引发了AopConfigException

时间:2015-11-30 10:08:34

标签: java spring spring-aop cglib

我正在使用Spring和Hibernate,并且我成功地在 Service 类的构造函数内自动装载存储库。当我尝试在服务类中添加@Transactional方法时,我得到一个AopConfigException,它是关于 CGLib 类的生成。

我的配置包含3个文件。 实现AppInitializer的{​​{1}}类,WebApplicationInitializer类,扩展WebMvcConfig,最后是WebMvcConfigurerAdapter类。

AppInitializer

PersistentContext

WebMvcConfig

public class AppInitializer implements WebApplicationInitializer {

    private static final String CONFIG_LOCATION = "com.project.app.config";
    private static final String MAPPING_URL = "/";

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        WebApplicationContext context = getContext();   
        servletContext.addListener(new ContextLoaderListener(context));
        ServletRegistration.Dynamic dispatcher = servletContext.addServlet("DispatcherServlet",
                new DispatcherServlet(context));
        dispatcher.setLoadOnStartup(1);
        dispatcher.addMapping(MAPPING_URL);

    }

    private AnnotationConfigWebApplicationContext getContext() {
        AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
        context.setConfigLocation(CONFIG_LOCATION);
        return context;
    }

PersistentContext

@EnableWebMvc
@Configuration
@ComponentScan(basePackages = { "com.project.app" })
public class WebMvcConfig extends WebMvcConfigurerAdapter {

    @Autowired
    private Environment env;

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {            
        registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
    }

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("hello");
    }

    @Bean
    public ApplicationContextProvider applicationContextProvider() {
        return new ApplicationContextProvider();
    }
}

存储库 INTERFACE 扩展了@Component @EnableJpaRepositories("com.project.app.services.repositories") @EnableTransactionManagement @PropertySource("classpath:application.properties") public class PersistenceContext { @Autowired private Environment env; @Bean @Primary public DataSource dataSource() throws ClassNotFoundException { DataSource ds = new DataSource(); ds.setUrl(env.getProperty(SystemSettings.DS_URL)); ds.setUsername(env.getProperty(SystemSettings.DS_USERNAME)); ds.setPassword(env.getProperty(SystemSettings.DS_PASSWORD)); ds.setDriverClassName(env.getProperty(SystemSettings.DS_DRIVER)); return ds; } @Bean LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) { LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean(); entityManagerFactoryBean.setDataSource(dataSource); entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter()); entityManagerFactoryBean.setPackagesToScan("com.project.app.services.entities"); // .. Set Properties.. entityManagerFactoryBean.setJpaProperties(jpaProperties); return entityManagerFactoryBean; } @Bean JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) { JpaTransactionManager transactionManager = new JpaTransactionManager(); transactionManager.setEntityManagerFactory(entityManagerFactory); return transactionManager; } }

StopRepository

CrudRepository

实体类。

StopJPA

@Repository
@RepositoryRestResource(collectionResourceRel = "stop", path = "stop")
public interface StopRepository extends CrudRepository<StopJPA, Long> {   
    @Override
    StopJPA save(StopJPA persisted);    
}

Service类实现:

StopService

@Entity
@Table(name = "stop")
public class StopJPA implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    private Long id;

    @Column(name = "stop_description")
    private String stopDescription;

    @Column(name = "id_stop", nullable = false)
    private String idStop;

    public StopJPA() {
    }

    public StopJPA(String stopDescription, String idStop) {
        this.stopDescription = stopDescription;
        this.idStop = idStop;
    }

    // .. Getters & Setters ..

}

不幸的是,当我尝试在服务器上运行它时,我得到了这个例外:

  

org.springframework.beans.factory.BeanCreationException:创建文件[C:.. \ RepoStopService.class]中定义名称为'repoStopService'的bean时出错:bean的初始化失败;   引起:org.springframework.aop.framework。 AopConfigException 无法生成类[class ..RepoStopService] 的CGLIB子类:此问题的常见原因包括使用final班级或不可见的班级;嵌套异常是java.lang.IllegalArgumentException:不能继承最终类类..RepoStopService

我知道Spring使用JDK代理或CGLib。如果我们自动装配一个接口(这里是它的存储库)的默认行为是有一个JDK代理? 需要改变什么才能使其发挥作用?

1 个答案:

答案 0 :(得分:6)

异常消息非常清楚

AopConfigException:Could not generate CGLIB subclass of class [class ..RepoStopService

首先,它抱怨它无法为您的服务创建代理,它根本没有提到您的存储库。您的服务是没有界面的类,它也是final

@Transactional是您服务中的方法。 Spring需要为您的服务创建一个代理,以便能够在此时启动和提交事务。由于您的服务未实现接口,因此它会尝试创建基于类的代理,但不能,因为您的类已标记为final

要修复,请删除final或创建一个接口,以便能够使用JDK动态代理而不是基于Cglib的类代理。

注意:根据所使用的Spring版本,在删除final关键字时仍然会失败,因为在早期版本中它还需要具有no-arg默认构造函数和你只有一个参数构造函数。