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

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

Производственное приложение работает под управлением 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.jar

Я также попытался добавить ткач 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.

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

4 ответа

Если нужно установить -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 или веб-сервером

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

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

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

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

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

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

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

-javaagent:/path/to/spring-instrument-4.0.0.RELEASE.jar -javaagent:/path/to/aspectjweaver-1.8.0.jar
Другие вопросы по тегам