如何使用没有Spring的AOP进行" @Transactional" -like注释

时间:2017-01-05 12:18:27

标签: jpa aop

我有一个非Spring应用程序。我想创建一个方面或类似的东西,它应该在之前和之后执行下面的代码,以使我的方法或类事务像Spring的@Transactional注释;

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

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

transaction.begin();

后;

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

我该怎么做?我在哪里可以找到类似的教程或示例?

编辑: 顺便说一句,需要在具有@Transactional的方法中使用em。

@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 个答案:

答案 0 :(得分: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();
}

驱动程序应用程序:

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);
    }
}

交易包装方面:

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

答案 1 :(得分:1)

我在原始版本旁边添加了另一个答案,因为似乎可以通过AspectJ从头开始重建@Transactional,以避免使用Spring容器:

实际上,Spring的声明式事务支持已经 是一个AspectJ方面。 Spring手册描述了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);