Как запустить Spring LoadTimeWeaving для репозитория JPA

Я пытаюсь добавить поддержку репозитория в проект Eclipselink JPA Spring. Eclipselink требует LoadTimeWeaving - хотя это не совсем так, позже я хотел бы, чтобы Aspects также работал.

Рабочее приложение работает под управлением Tomcat, и я мог бы уже закончить, если бы пошел дальше и не пытался создавать JUnits. У меня есть ощущение, что, возможно, у меня действительно проблема с 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));


}
}

Я пытаюсь запустить JUnit с этой виртуальной машиной ARG: -javaagent:C:\Users\Terry\.m2\repository\org\springframework\spring-agent\2.5.6.SEC03\spring-agent-2.5.6.SEC03 .банка

Я также пытался добавить вивер AspectJ, но это не помогло -javaagent:C:\Users\Terry\.m2\repository\org\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.

Что, конечно, верно. Этот загрузчик классов не поддерживает плетение. Но я очень-очень старался не использовать этот загрузчик. Любая помощь приветствуется


person Terry    schedule 01.05.2014    source источник


Ответы (4)


У меня аналогичная настройка, и для меня работает добавление следующих аргументов виртуальной машины для модульных тестов:

-javaagent:/path/to/spring-instrument-4.0.0.RELEASE.jar -javaagent:/path/to/aspectjweaver-1.8.0.jar
person JWK    schedule 01.05.2014
comment
На самом деле я использовал spring-instrument, но где-то читал, что вместо этого можно использовать spring-agent. К сожалению, ни один из них не работает. Спасибо хоть. - person Terry; 01.05.2014

Похоже, проблема заключалась в том, что в класс @Configuration я включил определение bean-компонента LoadTimeWeaver. Я также установил это значение в конструкторе EntityManagerFactory. Удалив это, я больше не получаю ошибку времени выполнения во время запуска контейнера Spring.

Глядя на консоль Spring, он говорит, что мои Entity Beans были преобразованы (сплетены), поэтому, возможно, ленивая загрузка все еще будет работать - у меня нет никаких ассоциаций БД, чтобы попробовать это в этом конкретном проекте.

Еще одно замечание: persistence.xml НЕ требуется, это не разрешено. Eclipselink искал другую копию файла persistence.xml, о которой я не знал, и это приводило к тому, что сущность, поддерживающая мой репозиторий, не была обнаружена.

Но прямо сейчас я считаю, что пример, который я опубликовал (за исключением bean-компонента loadTimeWeaving), примечательно, один из лучших или, по крайней мере, наиболее полных примеров - кто бы мог этого ожидать!

person Terry    schedule 02.05.2014

я не мог заставить вышеперечисленное работать. amazon aws не позволяет мне помещать jar инструментов в папку tomcat/lib, поэтому я не могу использовать подход -javaagent (поверьте мне, я пытался!). мне пришлось переключиться на статическое переплетение eclipselink

это не слишком сложно, требуется файл 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>

но обратите внимание, что он ДОЛЖЕН быть в вашем проекте, который содержит классы сущностей. я сделал ошибку, перетащив файл persistence.xml и плагин maven в файл pom.xml в проект моего веб-сайта, а не в проект моего домена.

person ChetPrickles    schedule 04.11.2016

Если нужно установить -javaagent с помощью maven, это можно сделать так:

        <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 или веб-сервером

person dchang    schedule 28.08.2017