2017-01-05 2 views
0

У меня есть приложение, отличное от Spring. Я хочу сделать аспект или что-то в этом роде, которое должно сделать код ниже до и после, чтобы сделать мой метод или класс транзакцией, например, аннотацией @Transactional от Spring;Как сделать «@Transactional» -подобную аннотацию с помощью АОП без пружины

До;

EntityManagerFactory emf = Persistence 
     .createEntityManagerFactory("AdvancedMapping"); 

/* Create EntityManager */ 
EntityManager em = emf.createEntityManager(); 
EntityTransaction transaction = em.getTransaction(); 

transaction.begin(); 

После;

transaction.commit(); 
em.close(); 

Как это сделать? Где я могу найти похожие учебники или примеры?

РЕДАКТИРОВАТЬ: Кстати, это необходимо для использования внутри метода, который имеет @Transactional.

@Transactional 
private int doSomething(String text) { 
    // Here I should have the "em" which was already taken in the aspect, 
    // so I can persist something in text 
    SomeEntityObject seo = new SomeEntityObject(); 
    seo.setText(text); 
    em.persist(seo); 
} 

ответ

2

Просто используйте AspectJ. Вы найдете учебники и другую документацию here. Если вы создаете свой проект с помощью Maven, вы хотите использовать AspectJ Maven plugin, чтобы упростить и автоматизировать компиляцию и ткачество.

Небольшой пример:

Маркер аннотаций: применение

package de.scrum_master.app; 

import java.lang.annotation.ElementType; 
import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 
import java.lang.annotation.Target; 

@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.METHOD) 
public @interface Transactional { 
    String value(); 
} 

Driver:

package de.scrum_master.app; 

public class Application { 
    public static void main(String[] args) { 
     Application application = new Application(); 
     application.doSomething("foo"); 
     application.doSomethingElse(11); 
     application.doSomething("bar"); 
     application.doSomethingElse(22); 
    } 

    @Transactional("please wrap me") 
    public int doSomething(String text) { 
     System.out.println("Doing something with '" + text + "'"); 
     return 42; 
    } 

    public void doSomethingElse(int number) { 
     System.out.println("Doing something else with number " + number); 
    } 
} 

Transaction обертку аспект:

package de.scrum_master.aspect; 

import javax.persistence.EntityManager; 
import javax.persistence.EntityManagerFactory; 
import javax.persistence.EntityTransaction; 
import javax.persistence.Persistence; 

import org.aspectj.lang.ProceedingJoinPoint; 
import org.aspectj.lang.annotation.Around; 
import org.aspectj.lang.annotation.Aspect; 

import de.scrum_master.app.Transactional; 

@Aspect 
public class TransactionalAspect { 
    @Around("execution(* *(..)) && @annotation(transactional)") 
    public Object wrapWithTransaction(ProceedingJoinPoint thisJoinPoint, Transactional transactional) throws Throwable { 
     System.out.println(thisJoinPoint + " -> " + transactional); 
//  EntityManagerFactory emf = Persistence.createEntityManagerFactory("AdvancedMapping"); 
//  EntityManager em = emf.createEntityManager(); 
//  EntityTransaction transaction = em.getTransaction(); 
     try { 
      Object result = thisJoinPoint.proceed(); 
//   transaction.commit(); 
      return result; 
     } 
     catch (Exception e) { 
//   transaction.rollback(); 
      throw e; 
     } 
     finally { 
//   em.close(); 
     } 
    } 
} 

журнала Консоль с JPA вещи закомментирована:

execution(int de.scrum_master.app.Application.doSomething(String)) -> @de.scrum_master.app.Transactional(value=please wrap me) 
Doing something with 'foo' 
Doing something else with number 11 
execution(int de.scrum_master.app.Application.doSomething(String)) -> @de.scrum_master.app.Transactional(value=please wrap me) 
Doing something with 'bar' 
Doing something else with number 22 
+0

Спасибо. Как мне получить «em» внутри метода? В этом примере в методе doSomething() мне нужно «сохранить/обновить/удалить» объекты с помощью экземпляра EntityManager. –

+0

Я могу только сказать вам, если вы покажете мне свой код. Как вы могли бы получить менеджер объектов из аннотированных методов? Это параметр? Это «это» или член «этого»? В принципе, если я знаю, как вы его получите, я могу рассказать вам, как ваш аспект может получить к нему доступ. Но я действительно рекомендую вам ознакомиться с введением AspectJ. – kriegaex

+0

Не совсем. Сначала я подумал, что вы хотите, чтобы менеджер объектов (EM) из аннотированного метода входил в аспект. Теперь это выглядит наоборот, т. Е. Вы хотите создать экземпляр EM в этом аспекте, а затем получить доступ к нему из аннотированного метода, верно?Это также возможно, но еще один вопрос: сколько экземпляров EM вам нужно? Один за транзакцию? Один за класс с аннотированными методами? Один за приложение (singleton)? Мой ответ зависит от вашего. – kriegaex

1

Я добавляю еще один ответ рядом с моей исходной, поскольку, как представляется, является альтернативой восстановлению @Transactional с нуля с помощью AspectJ только для того, чтобы избежать используя Spring контейнер:

на самом деле, декларативная поддержка транзакций для Spring уже является аспекта AspectJ. Руководство по весне описывает how to use @Transactional with AspectJ without the Spring container. Вам даже не нужна конфигурация Spring XML, но вы можете вставить диспетчер транзакций непосредственно в аспект (фрагмент кода, указанный в руководстве):

// construct an appropriate transaction manager 
DataSourceTransactionManager txManager = new DataSourceTransactionManager(getDataSource()); 

// configure the AnnotationTransactionAspect to use it; 
// this must be done before executing any transactional methods 
AnnotationTransactionAspect.aspectOf().setTransactionManager(txManager); 
Смежные вопросы