如何为JPA存储库运行Spring LoadTimeWeaving

时间:2014-05-01 15:01:53

标签: spring jpa junit eclipselink load-time-weaving

我正在尝试将Repository支持添加到Eclipselink JPA Spring项目中。 Eclipselink需要LoadTimeWeaving - 即使这不是绝对正确的,我后来也想让Aspects工作。

生产应用程序在Tomcat下运行,如果我已经完成并且没有尝试创建JUnit,我现在可能已经完成了。我有一种感觉,也许我真正拥有的是一个Eciplse(STS 3.4)问题,因为它似乎忽略了我的替代类加载器。但这似乎是基本的,这必须奏效,而且我做错了。

我只使用Annotations和Java配置。以下相关代码。

配置

@Configuration
@Profile("data")
@EnableJpaRepositories(basePackages="com.xxx.ieexb.repository",transactionManagerRef="transactionManager",entityManagerFactoryRef="entityManagerFactory")
@ComponentScan(basePackages= {"com.xxx.ieexb.jpa"
                    ,"com.xxx.ieexb.repository"})
@EnableTransactionManagement
@EnableLoadTimeWeaving
@ImportResource("classpath:/properties-config.xml")
public class IeexbDataContextConfig {
@Value("#{ieexbProperties['com.xxx.ieexb.dataSource.Url']}")
public String dataSourceUrl;
@Value("#{ieexbProperties['com.xxx.ieexb.dataSource.Username']}")
public String dataSourceUsername;
@Value("#{ieexbProperties['com.xxx.ieexb.dataSource.Password']}")
public String dataSourcePassword;
@Value("#{ieexbProperties['com.xxx.ieexb.persistenceUnitName']}")
public String persistenceUnitName;

@Autowired
EntityManagerFactory entityManagerFactory;

@Bean()
public DriverManagerDataSource dataSource() {
    DriverManagerDataSource dataSource = new DriverManagerDataSource();
    dataSource.setDriverClassName("org.springframework.jdbc.datasource.DriverManagerDataSource");
    dataSource.setUrl(dataSourceUrl);
    dataSource.setUsername(dataSourceUsername);
    dataSource.setPassword(dataSourcePassword);
    return dataSource;
}

@Bean()
EclipseLinkJpaVendorAdapter eclipseLinkJpaVendorAdapter() {
    EclipseLinkJpaVendorAdapter eclipseLinkJpaVendorAdapter = new EclipseLinkJpaVendorAdapter();
    eclipseLinkJpaVendorAdapter.setShowSql(true);
    eclipseLinkJpaVendorAdapter.setGenerateDdl(false);
    eclipseLinkJpaVendorAdapter.setDatabasePlatform("org.eclipse.persistence.platform.database.OraclePlatform");
    return eclipseLinkJpaVendorAdapter;
}

@Bean()
EclipseLinkJpaDialect jpaDialect() {
    EclipseLinkJpaDialect jpaDialect = new EclipseLinkJpaDialect();
    return jpaDialect;
}

@Bean()
public FactoryBean<EntityManagerFactory> entityManagerFactory() {
    LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
    //TODO Does this @Configuration do away with need for persistence.xml?
    //emf.setPersistenceXmlLocation("classpath:persistence.xml");
    emf.setPersistenceUnitName(persistenceUnitName);
    emf.setDataSource(dataSource());
    emf.setLoadTimeWeaver(loadTimeWeaver());
    emf.setJpaDialect(new EclipseLinkJpaDialect());
    emf.setJpaVendorAdapter(eclipseLinkJpaVendorAdapter());
    //emf.setPersistenceProvider(persistenceProvider());
    return emf;
}

@Bean()
public LoadTimeWeaver loadTimeWeaver() {
    LoadTimeWeaver loadTimeWeaver = new ReflectiveLoadTimeWeaver();
    return loadTimeWeaver;
}
}

死亡的简单实体(删除了一些真正无聊的列):

@Entity
@Cacheable(false)
@Table(name="PENDING_QUEUE"
, uniqueConstraints = @UniqueConstraint(columnNames="IEEXB_ID,QUEUE_TIMESTAMP")
)
public class PendingQueue implements Serializable {

private static final long serialVersionUID = 1L;

@EmbeddedId
@AttributeOverrides( {
    @AttributeOverride(name="ieexbId", column=@Column(name="IEEXB_ID", nullable=false) ),
    @AttributeOverride(name="queueTimestamp", column=@Column(name="QUEUE_TIMESTAMP", nullable=false) ) } )
private PendingQueueId id;
@Column(name="IE_USER", nullable=false, length=21)
private String ieUser;
@Column(name="COMMAND_TYPE", nullable=false, length=3)
private String commandType;


public PendingQueue() {
    ;
}

public PendingQueue(PendingQueueId id, String ieUser, String commandType) {
    super();
    this.id = id;
    this.ieUser = ieUser;
    this.commandType = commandType;
}

public PendingQueueId getId() {
    return id;
}

public void setId(PendingQueueId id) {
    this.id = id;
}

public String getIeUser() {
    return ieUser;
}

public void setIeUser(String ieUser) {
    this.ieUser = ieUser;
}

public String getCommandType() {
    return commandType;
}

public void setCommandType(String commandType) {
    this.commandType = commandType;
}
....
}

当然是存储库:

@Repository
public interface PendingQueueRepository extends CrudRepository<PendingQueue, PendingQueueId> {
List<PendingQueue> findByIeUser(String ieUser);
}

最后是JUnit:

@RunWith(SpringJUnit4ClassRunner.class)
@ActiveProfiles(profiles = {"data"})
@ContextConfiguration(classes = IeexbDataContextConfig.class, loader = AnnotationConfigContextLoader.class)
public class TestPendingQueue {
@Autowired
PendingQueueRepository pendingQueueRepository;

@Test
public void testFindByIeUser() {
    List<PendingQueue> results = pendingQueueRepository.findByIeUser("JPA.XXX.BOB1");
    System.out.println("Found Items:" + results.size());
    System.out.println("First item is:" + results.get(0));


}
}

我正在尝试使用此VM ARG运行JUnit: -javaagent:C:\ Users \ Terry \ .m2 \ repository \ org \ springframework \ spring-agent \ 2.5.6.SEC03 \ spring-agent-2.5.6.SEC03.jar

我也尝试过添加AspectJ weaver,但它没有帮助 -javaagent:C:\用户\特里\的.m2 \库\有机\ AspectJ的\ aspectjweaver \ 1.8.0 \ aspectjweaver-1.8.0.jar

我没有尝试过Spring Tomcat织布工,但这似乎不是正确的方向。我读过人们然后遇到了JUnit找到类文件的问题。

没有粘贴在相当庞大的堆栈跟踪中,所有这一切归结为:

Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.springframework.instrument.classloading.LoadTimeWeaver
 com.xxx.ieexb.config.IeexbDataContextConfig.loadTimeWeaver()] threw exception; nested exception is java.lang.IllegalStateException: ClassLoader [sun.misc.Launcher$AppClassLoader] does NOT provide an 'addTransformer(ClassFileTransformer)' method.

这当然是真的。该类加载器不支持编织。但我非常努力地不使用那个装载机。任何帮助表示赞赏

4 个答案:

答案 0 :(得分:0)

我有类似的设置,并为我添加以下用于单元测试的VM args:

-javaagent:/path/to/spring-instrument-4.0.0.RELEASE.jar -javaagent:/path/to/aspectjweaver-1.8.0.jar

答案 1 :(得分:0)

看来问题是在@Configuration类中我包含了一个LoadTimeWeaver bean的定义。我还在EntityManagerFactory构造函数中设置了该值。通过删除,我不再在spring容器启动期间收到运行时错误。

查看Spring控制台,它说我的实体Bean被转换(编织)所以也许懒惰加载仍然可以工作 - 我没有任何数据库关联在这个特定的项目中尝试它。

另一个注意事项是, persistence.xml不是必需的不允许这样做。 Eclipselink正在寻找另一个我不知道的persistence.xml副本,这导致实体支持我的存储库不被发现。

但是现在我相信我发布的示例(减去loadTimeWeaving bean)显然是最好的,或者至少是最完整的示例之一 - 谁曾期望过!

答案 2 :(得分:0)

我无法完成上述工作。亚马逊aws不允许我把仪器jar放在tomcat / lib文件夹中,所以我不能使用-javaagent方法(相信我,我试过!)。我不得不切换到eclipselink static weaving

它不太难,需要一个persistence.xml文件,但是如果你已经使用了带注释的配置,它可以简短:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
             xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    <persistence-unit name="ADD_NAME_HERE">
        <!--this is necessary for the eclipselink static weaving maven plugin-->
        <!--this setting auto-detects entities in the project-->
        <exclude-unlisted-classes>false</exclude-unlisted-classes>
    </persistence-unit>
</persistence>

但请注意,它必须位于包含实体类的项目中。我犯了将pom.xml文件中的persistence.xml文件和maven插件放入我的网站项目而不是我的域项目的错误。

答案 3 :(得分:0)

如果需要通过maven设置-javaagent,它可以这样做:

        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.20</version>
                <configuration>
                    <argLine>
                        -javaagent:"${settings.localRepository}/org/springframework/spring-instrument/${org.springframework.version}/spring-instrument-${org.springframework.version}.jar"
                    </argLine>
                </configuration>
            </plugin>
        </plugins>

(只需设置$ {org.springframework.version}的属性或替换相应的版本) 这样它与您的项目相关联,而不是与您的jvm或webserver

相关联