Как настроить AspectJ с помощью функции Time Time Weaving без интерфейса
В моем проекте я в настоящее время использую AspectJ (а не только Spring АОП из-за некоторого ограничения) с плетением во время компиляции. Чтобы ускорить разработку на Eclipse, я хочу сделать плетение в Время загрузки. Мне это удается, но с одним основным ограничением: с помощью интерфейса для моей службы, который содержит некоторые транзакционные методы. Если я объявляю сервис с его реализацией, а не его интерфейсом, в классе вызывающего абонента нет переплетения и, следовательно, транзакции не поддерживаются.
Итак, , если он поддерживается AspectJ, как настроить AspectJ с загрузкой времени без интерфейса?
Я создал небольшой проект, который воспроизводит проблему:
Не удалось выполнить следующий тест.
Следующий тест будет успешным, если:
-
заявленная служба объявляется своим интерфейсом вместо своей реализации (т.е. заменяет услугу "@Inject MyServiceImpl" на "услугу @Inject MyService" ), тест преуспевает.
-
пение выполняется во время компиляции (контекст приложения конфигурации, POM и Spring, в данном случае, очевидно, отличается). Но моя цель - сделать плетение в режиме загрузки, чтобы избежать фазы ткачества каждый раз, когда я сохраняю файл Java.
-
Spring Вместо AspectJ используется AOP (tx: управляемый аннотацией режим = "прокси" ), то есть прокси-решение. Но в этом случае мы столкнулись с проблемой самозапуска, т.е. Метод внутри целевого объекта, вызывающий какой-либо другой метод целевого объекта, не приведет к фактической транзакции во время выполнения, даже если вызываемый метод отмечен @Transactional.
AspectJ-LTW/SRC/тест/Java/MyCompany/aspectj_ltw/MyServiceImplTest.java
package mycompany.aspectj_ltw;
import static junit.framework.Assert.assertTrue;
import javax.inject.Inject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:/META-INF/spring/applicationContext.xml" })
public class MyServiceImplTest {
@Inject
MyServiceImpl service;
@Test
public void shouldBeExecutedInTransaction() {
assertTrue(this.service.isExecutedInTransaction());
}
}
AspectJ-LTW/SRC/Основной/Java/MyCompany/aspectj_ltw/MyService.java
package mycompany.aspectj_ltw;
public interface MyService {
boolean isExecutedInTransaction();
}
AspectJ-LTW/SRC/Основной/Java/MyCompany/aspectj_ltw/MyServiceImpl.java
package mycompany.aspectj_ltw;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationManager;
@Service
public class MyServiceImpl implements MyService {
@Transactional
public boolean isExecutedInTransaction() {
return TransactionSynchronizationManager.isActualTransactionActive();
}
}
AspectJ-LTW/SRC/тест/ресурсы/META-INF/applicationContext.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<context:component-scan base-package="mycompany.aspectj_ltw" />
<context:load-time-weaver aspectj-weaving="on" />
<aop:config proxy-target-class="true"/>
<aop:aspectj-autoproxy proxy-target-class="true"/>
<tx:annotation-driven mode="aspectj"
transaction-manager="transactionManager" proxy-target-class="true" />
<bean class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close" id="dataSource">
<property name="driverClassName" value="org.h2.Driver" />
<property name="url" value="jdbc:h2:mem:mydb" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
id="transactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
</beans>
AspectJ-LTW/SRC/тест/ресурсы/META-INF/aop.xml
<!DOCTYPE aspectj PUBLIC
"-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
<weaver options="-showWeaveInfo -debug -verbose -XmessageHandlerClass:org.springframework.aop.aspectj.AspectJWeaverMessageHandler">
<include within="mycompany.aspectj_ltw..*"/>
</weaver>
</aspectj>
AspectJ-LTW\pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>mycompany</groupId>
<artifactId>aspectj-ltw</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>aspectj-ltw</name>
<properties>
<spring.version>3.0.5.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.7.0</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.7.0</version>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.2.143</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>0.9.24</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>0.9.24</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>1.6.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<forkMode>always</forkMode>
<argLine>
-javaagent:C:/maven-2_local_repo/org/springframework/spring-instrument/3.0.5.RELEASE/spring-instrument-3.0.5.RELEASE.jar
</argLine>
</configuration>
</plugin>
</plugins>
</build>
</project>
аргументы VM для запуска теста:
-javaagent:C:/maven-2_local_repo/org/springframework/spring-instrument/3.0.5.RELEASE/spring-instrument-3.0.5.RELEASE.jar
Ответы
Ответ 1
Если я не ошибаюсь, проблема здесь не связана с AspectJ, а скорее с тем, как все работает в точном примере использования JUnit. При запуске теста сначала загружается класс MyServiceImplTest
, прежде чем будет создан контекст Spring (вам нужны аннотации тестового класса, чтобы получить соответствующие места для бегунов и конфигураций), поэтому до того, как был задействован любой механизм Spring AOP, То есть, по крайней мере, объяснение, которое я придумал, когда я столкнулся с той же самой ситуацией несколько месяцев назад... Поскольку javaagent существует от запуска JVM, нужно было бы полностью прочитать/понять код ткача точно объясните, почему здесь это не удается (я не сделал: p).
Так или иначе, тип MyServiceImplTest
, вместе со всеми его типами-членами, которые загружаются с ним, - это также относится к типам в сигнатурах методов, - нельзя сплести.
Чтобы обойти это:
- либо избегать использования сплетенных типов в элементах тестового класса и подписи методов (например, используя такие интерфейсы, как вы)
-
или добавьте твитер AspectJ к вашим javaagents (в дополнение к spring -инструмент); с этим, если я правильно помню, Spring должен иметь возможность правильно работать на своих механизмах на основе AOP:
-javaagent:/maven-2_local_repo/org/aspectj/aspectjweaver/1.7.0/aspectjweaver-1.7.0.jar -javaagent:/maven-2_local_repo/org/springframework/ spring -инструмент/3.0.5. RELEASE/spring -instrument-3.0.5.RELEASE.jar
Nota: в вашем META-INF/aop.xml
может потребоваться добавить опцию -Xreweavable
weaver.
Ответ 2
Прежде всего, если вы используете maven, установите pom.xml:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-instrument</artifactId>
<version>3.1.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.7</version>
</dependency>
Затем вам пришлось скомпилировать свой код с помощью компилятора aspectj.
Этот компилятор создает файл aop.xml в файле META-INF/aop.xml
(Я использую eclipse sts)
После этого я хочу запустить тест Junit.
Таким образом, вы должны установить свои аргументы VM в окне конфигурации запуска eclipse:
-javaagent: ${ASPECTJ_WEAVER_1.7}\aspectjweaver-1.7.0.jar -javaagent: ${SPRING_INSTRUMENT}\ spring -инструмент-3.1.2.RELEASE.jar
где ${ASPECTJ_WEAVER_1.7} ${SPRING_INSTRUMENT} - это переменная окружения. Используйте кнопку var для создания этих vars (находится в нижней правой части окна). Эти vars нацелены на папки, в которых расположены aspectjweaver-1.7.0.jar и spring -instrument-3.1.2.RELEASE.jar. Следуйте за asistant, чтобы сделать это. Это не сложно.
Позаботьтесь о том, чтобы предыдущие строки javaagent не имели какого-либо невидимого странного характера или подобного. Это звучит странно, но мне пришлось переписать несколько раз ту же строку, пока затмение не сообщит, что эта строка в порядке.
Затем вы можете запустить тест Junit.
Первое, что вы можете увидеть, - это анимированная загрузка. Позже вы увидите загрузку spring... и после этого ваш тест будет запущен, у вас не возникнет проблема с spring или аналогичная.
Это тяжелый процесс.
Я надеюсь, что эта информация поможет вам
Привет