2014-12-30 12 views
7

Tôi đã tạo một Aspect chứa chú thích @Transactional. Lời khuyên của tôi đang được gọi như mong đợi, nhưng thực thể mới AuditRecord không bao giờ được lưu vào cơ sở dữ liệu, có vẻ như chú thích @Transactional của tôi không hoạt động.Spring @Transactional in a Aspect (AOP)

@Aspect 
@Order(100) 
public class ServiceAuditTrail { 

private AppService appService; 
private FooRecordRepository fooRecordRepository; 

@AfterReturning("execution(* *.app.services.*.*(..))") 
public void logAuditTrail(JoinPoint jp){ 
    Object[] signatureArgs = jp.getArgs(); 
    String methodName = jp.getSignature().getName(); 

    List<String> args = new ArrayList<String>(); 
    for(Object arg : signatureArgs){ 
     args.add(arg.toString()); 
    } 

    createRecord(methodName, args); 
} 

@Transactional 
private void createRecord(String methodName, List<String> args){ 
    AuditRecord auditRecord = new AuditRecord(); 
    auditRecord.setDate(new Date()); 
    auditRecord.setAction(methodName); 
    auditRecord.setDetails(StringUtils.join(args, ";")); 
    auditRecord.setUser(appService.getUser()); 
    fooRecordRepository.addAuditRecord(auditRecord); 
} 

    public void setAppService(AppService appService) { 
     this.appService = appService; 
    } 

    public void setFooRecordRepository(FooRecordRepository fooRecordRepository) { 
     this.fooRecordRepository= fooRecordRepository; 
    } 

} 

Bối cảnh đậu là như sau:

<tx:annotation-driven transaction-manager="txManager.main" order="200"/> 

<aop:aspectj-autoproxy /> 

<bean id="app.aspect.auditTrail" class="kernel.audit.ServiceAuditTrail"> 
    <property name="appService" ref="app.service.generic" /> 
    <property name="fooRecordRepository" ref="domain.repository.auditRecord" /> 
</bean> 

pointcut tôi hiện đang chặn các giao diện duy nhất (giao diện dịch vụ). Các phương thức dịch vụ có thể hoặc không thể giao dịch. Nếu phương thức dịch vụ là giao dịch, tôi muốn giao dịch đó được khôi phục nếu lời khuyên không thành công vì một lý do nào đó.

Câu hỏi của tôi: Tại sao chú thích giao dịch bị bỏ qua? Đây là lần đầu tiên tôi xây dựng dịch vụ AOP với Spring, tôi cũng sẽ hoan nghênh mọi cải tiến về kiến ​​trúc hoặc triển khai.

Cảm ơn!

Trả lời

9

Vào mùa xuân, @Transactional hoạt động bằng cách tạo proxy cho lớp của bạn (proxy Java hoặc cglib) và chặn phương thức được chú thích. Điều này có nghĩa là @Transactional không hoạt động nếu bạn đang gọi phương thức được chú thích từ phương thức khác của cùng một lớp.

Chỉ cần di chuyển phương thức createRecord sang một lớp mới (đừng quên biến nó thành Spring bean) và nó sẽ hoạt động.

3

Câu hỏi hay. Nếu bạn phải rollback/cam kết các giao dịch bạn có thể trực tiếp cấu hình các giao dịch mùa xuân như đã đề cập here.

Làm phương pháp này không yêu cầu bạn thêm @Transactional vào từng lớp/phương pháp theo cách thủ công.

Cấu hình mùa xuân bên dưới (được sao chép từ liên kết tham chiếu). Thay vì viết các cố vấn tùy chỉnh/các phím tắt, chỉ cần thêm cấu hình trong tệp context.xml ứng dụng vào mùa xuân cùng với các cố vấn/các phím tắt của bạn.

<bean id="fooService" class="x.y.service.DefaultFooService"/> 

    <!-- the transactional advice (what 'happens'; see the <aop:advisor/> bean below) --> 
    <tx:advice id="txAdvice" transaction-manager="txManager"> 
     <!-- the transactional semantics... --> 
     <tx:attributes> 
      <!-- all methods starting with 'get' are read-only --> 
      <tx:method name="get*" read-only="true"/> 
      <!-- other methods use the default transaction settings (see below) --> 
      <tx:method name="*"/> 
     </tx:attributes> 
    </tx:advice> 

    <!-- ensure that the above transactional advice runs for any execution 
     of an operation defined by the FooService interface --> 
    <aop:config> 
     <aop:pointcut id="fooServiceOperation" expression="execution(* x.y.service.FooService.*(..))"/> 
     <aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/> 
    </aop:config> 

    <!-- don't forget the DataSource --> 
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> 
     <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/> 
     <property name="url" value="jdbc:oracle:thin:@rj-t42:1521:elvis"/> 
     <property name="username" value="scott"/> 
     <property name="password" value="tiger"/> 
    </bean> 

    <!-- similarly, don't forget the PlatformTransactionManager --> 
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 
     <property name="dataSource" ref="dataSource"/> 
    </bean> 

ref:

  1. mùa xuân giao dịch: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/transaction.html
Các vấn đề liên quan