【问题标题】:How to run Spring LoadTimeWeaving for JPA Repository如何为 JPA 存储库运行 Spring LoadTimeWeaving
【发布时间】:2014-05-01 15:01:53
【问题描述】:

我正在尝试将存储库支持添加到 Eclipselink JPA Spring 项目。 Eclipselink 需要 LoadTimeWeaving——尽管这不是绝对正确的,但我以后想让 Aspects 也能正常工作。

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

我只使用注解和 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 编织器,但没有帮助 -javaagent:C:\Users\Terry\.m2\repository\org\aspectj\aspectjweaver\1.8.0\aspectjweaver-1.8.0.jar

我没有尝试过 Spring Tomcat weaver,但这似乎不是正确的方向。我读到有人在 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.

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

【问题讨论】:

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


    【解决方案1】:

    我有类似的设置,添加以下用于单元测试的 VM 参数对我有用:

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

    【讨论】:

    • 我实际上一直在使用 spring-instrument,但在某处阅读以使用 spring-agent 代替。不幸的是,两者都不起作用。不过还是谢谢。
    【解决方案2】:

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

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

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

    但现在我相信我发布的示例(减去 loadTimeWeaving bean)显然是最好的示例之一,或者至少是最完整的示例之一 - 谁能预料到呢!

    【讨论】:

      【解决方案3】:

      我无法使上述工作。 amazon 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 插件放入我的网站项目而不是我的域项目中。

      【讨论】:

        【解决方案4】:

        如果需要通过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 或网络服务器相关联

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-11-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-01-28
          • 2014-05-18
          • 2017-05-26
          • 2019-08-02
          相关资源
          最近更新 更多