Spring AOP 一个方法一个 class 在另一个之前

Spring AOP one method of a class before another

我有一个使用 Spring Core、Spring MVC、Hibernate 的应用程序。 有很多 DAO classes 在像这样的每个方法中获得新的 Hibernate 会话

    @Autowired
private SessionFactory sessionFactory;

private Session session;

private void createSession() {
    session =  sessionFactory.openSession();
}


@Override
public List<User> listUsers() {
    createSession();
    List users;

    users = session.createQuery("from User").list();
    session.close();

    return users;
}

我想使用 AOP 在那些 class 方法之前执行 createSession 方法,但不知道该怎么做。

我所做的就是这方面

@Configuration
@Aspect
public class DaoSessionLifeCycle {

    @Before(value = "execution(* ua.com.alistratenko.dao.UserDaoImp.listUsers(..))")
    public void openSession(JoinPoint joinPoint){

        System.out.println("izi");
    }
}

除了@Bogdan 说的,看看CrudRepositoryJpaRepository,会节省你很多时间。另外,在我看来,@Aspect 类 被注释为 @Component 而不是 @Configuration.

因为你仍然没有提供MCVE或者至少一些更多(更现实)的示例代码,我只能推测并提供一个示意性的答案。

顺便说一句,我在这里使用的是 AspectJ 而不是 Spring AOP,但它应该以相同的方式工作。

Dummy classes 使示例代码编译:

package ua.com.alistratenko.dao;

public class User {
  String name;

  public User(String name) {
    this.name = name;
  }

  @Override
  public String toString() {
    return "User [name=" + name + "]";
  }
}
package ua.com.alistratenko.dao;

import java.util.ArrayList;
import java.util.List;

public class QueryResult {
  public List<User> list() {
    List<User> users = new ArrayList<>();
    users.add(new User("jane"));
    users.add(new User("joe"));
    return users;
  }
}
package ua.com.alistratenko.dao;

public class Session {
  public QueryResult createQuery(String string) {
    return new QueryResult();
  }

  public void close() {}
}
package ua.com.alistratenko.dao;

public class SessionFactory {
  public Session openSession() {
    return new Session();
  }
}

申请class:

我改变了什么?

  • 在 Spring 中,您将使用 @Autowired 而不是自己创建会话工厂。我这样做是为了能够在没有 Spring.
  • 的情况下 运行 我的示例代码
  • 为能够访问会话工厂以及会话本身的方面添加了一些 setters/getters
  • 删除createSession()(代码迁移到方面,见下文)
  • listUsers()
  • 中不再有样板文件混乱
  • 为演示目的添加了 main 方法
package ua.com.alistratenko.dao;

import java.util.List;

public class UserDaoImp {
  private SessionFactory sessionFactory = new SessionFactory();
  private Session session;

  public SessionFactory getSessionFactory() { return sessionFactory; }
  public Session getSession() { return session; }
  public void setSession(Session session) { this.session = session; }

  public List<User> listUsers() {
    return session.createQuery("from User").list();
  }

  public static void main(String[] args) {
    new UserDaoImp().listUsers();
  }
}

看点:

为了在拦截方法调用之前+之后做一些事情,请使用@Around

package de.scrum_master.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
//import org.springframework.stereotype.Component;

import ua.com.alistratenko.dao.UserDaoImp;

//@Component
@Aspect
public class DaoSessionLifeCycle {
  @Around("execution(public * listUsers(..)) && target(dao)")
  public Object openSession(ProceedingJoinPoint thisJoinPoint, UserDaoImp dao) throws Throwable {
    try {
      System.out.println("Creating session");
      dao.setSession(dao.getSessionFactory().openSession());
      System.out.println("Calling " + thisJoinPoint.getSignature());
      return thisJoinPoint.proceed();
    }
    finally {
      try {
        System.out.println("Closing session");
        dao.getSession().close();
      }
      catch (Exception e) {}
    }
  }
}

控制台日志:

Creating session
Calling List ua.com.alistratenko.dao.UserDaoImp.listUsers()
Closing session

现在有几个悬而未决的问题:

  • 您只想处理这个 class 还是一个基础 class 的所有子 class 或所有 DAO 通用的已实现接口?那么切入点看起来会有所不同。
  • 您只想拦截方法 listUsers() 还是其他方法?由于您没有显示更多代码,因此除了您之外没有人知道。根据您的回答,切入点也会有所不同。
  • 您真的想全部手动完成,还是听从其他用户的建议并使用机载 Spring 工具来管理您的交易?我不知道 Spring,所以我不能告诉你。我只是为您的问题提供了与方面相关的答案。