W moim projekcie używam obecnie AspectJ (nie tylko Spring AOP ze względu na pewne ograniczenia) z tkaniem w czasie kompilacji. W celu przyspieszenia rozwoju Eclipse, chcę zrobić tkactwo w czasie ładowania. Udaje mi się to zrobić, ale z jednym wielkim ograniczeniem: używanie interfejsu dla mojej usługi, który zawierał pewne metody transakcyjne. Jeśli deklaruję usługę z jej implementacją zamiast interfejsu, w klasie wywołującej nie ma tkania, więc nie jest obsługiwana żadna transakcja.Jak skonfigurować AspectJ z czasem ładowania Tkanie bez interfejsu
Więc jeśli jest obsługiwany przez AspectJ, jak skonfigurować AspectJ z Load Time Weaving bez interfejsu?
stworzyłem mały projekt, który odtworzenia problemu:
następujący test nie powiedzie się.
Poniższa próba się uda, jeżeli:
wstrzyknięta usługa jest zadeklarowana z interfejsem zamiast jego realizacji (tj zastąpić „usługi @Inject MyServiceImpl” przez „@Inject usługi MojaUsluga”), test się uda .
Tkanie wykonywane jest podczas kompilacji (konfiguracja, POM & Kontekst aplikacji wiosennej jest oczywiście inny w tym przypadku). Ale moim celem jest tkanie w czasie ładowania, aby uniknąć fazy tkania za każdym razem, gdy zapisuję plik Java.
Spring AOP (tx: tryb sterowany adnotacją = "proxy"), czyli rozwiązanie oparte na proxy, jest używane zamiast AspectJ. Ale w tym przypadku napotkaliśmy problem z samo-wywoływaniem, tj. Metoda w obiekcie docelowym wywołująca inną metodę obiektu docelowego, nie doprowadzi do rzeczywistej transakcji w czasie wykonywania, nawet jeśli wywołana metoda jest oznaczona jako @Transactional.
AspectJ LTW/src/test/Java/mojafirma/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/main/Java/mojafirma/aspectj_ltw/MyService.java
package mycompany.aspectj_ltw;
public interface MyService {
boolean isExecutedInTransaction();
}
AspectJ LTW/src/main/Java/mojafirma/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/test/resources/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/test/resources/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 argumenty aby uruchomić test:
-javaagent:C:/maven-2_local_repo/org/springframework/spring-instrument/3.0.5.RELEASE/spring-instrument-3.0.5.RELEASE.jar
dziękuję! Myślę, że to całkiem bliskie wyjaśnienie tego, co się dzieje.Nie jestem w 100% pewny, ponieważ z tego, co słyszałem, Spring używa 2-klasowych ładowarek i 2-klasowych przepustek - klasa testowa i jej referencje powinny być najpierw załadowane do pierwszego programu ładującego, analizowanych adnotacji itp., Ale potem zostają odrzucone i ładowane przez AspectJ pod warunkiem, że ładowarka, która robi tkactwo ... Teoretycznie powinno to pozwolić na prawidłowe tkanie, ale jakoś tak nie jest. Spróbuję dodać Aspirejweaver javaagent i/lub opcje do zmiany, aby sprawdzić, czy to naprawi! – alexandroid
f *** ng .... genialny. Właśnie odetchnąłem z największym oddechem, po kilku frustrujących kilku godzinach, które mam już od jakiegoś czasu po otrzymaniu twojej rady. Dla zapisu, w tym 'aspectjweaver' wraz z' spring-instrument' jako javaagent, umożliwiło mi prawidłowe tasowanie czasu ładowania w aplikacji wiosennych butów, testy jednoczęściowe obejmowały – drewmoore
@drewmoore Pracuję z wiosennym butem Aplikacja mvc i potrzeba wywołania jednej metody z innej metody w obrębie tej samej klasy kontrolera, gdzie ta ostatnia metoda jest opisana przy użyciu '@ Async'. Powiedziano mi, że nie jest to możliwe, chyba że włączę tryb proxy AspectJ i dostarczy tkacz. Czy to jest podobne do tego, co robisz? –