Spring AOP один метод класса перед другим - PullRequest
0 голосов
/ 02 мая 2018

У меня есть приложение, использующее Spring Core, Spring MVC, Hibernate. Есть много классов DAO, которые получают новый сеанс 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 для выполнения метода createSession перед этими методами класса, но не могу понять, как это сделать.

Все, что я сделал, был этот аспект

@Configuration
@Aspect
public class DaoSessionLifeCycle {

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

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

Ответы [ 2 ]

0 голосов
/ 02 мая 2018

Поскольку вы до сих пор не предоставили MCVE или хотя бы еще некоторый (и более реалистичный) пример кода, я могу только строить догадки и давать схематический ответ.

Кстати, я использую AspectJ, а не Spring AOP, но он должен работать там же.

Пустые классы для компиляции примера кода:

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

Класс применения:

Что я изменил?

  • В Spring вы будете использовать @Autowired вместо того, чтобы создавать фабрику сессий самостоятельно. Я просто сделал это, чтобы иметь возможность запускать мой пример кода без Spring.
  • Добавлены некоторые установщики / получатели для аспекта, чтобы иметь возможность доступа к фабрике сеансов, а также к самому сеансу
  • Удалено createSession() (код перенесен в аспект, см. Ниже)
  • Нет больше беспорядка в шаблоне listUsers()
  • Добавлен основной метод для демонстрационных целей
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

Теперь есть несколько открытых вопросов:

  • Вы хотите обрабатывать только этот один класс или, может быть, все подклассы базового класса или реализованный интерфейс, общий для всех ваших DAO? Тогда pointcut будет выглядеть иначе.
  • Вы хотите перехватить только метод listUsers() или, может быть, другие методы? Поскольку вы не показали больше кода, никто, кроме вас, не может знать. Pointcut также будет выглядеть по-разному в зависимости от вашего ответа.
  • Вы действительно хотите сделать все это вручную или, возможно, последуете советам других пользователей и используете встроенные инструменты Spring для управления своими транзакциями? Я понятия не имею о весне, поэтому не могу вам сказать. Я просто давал ответ на ваш вопрос, который был связан с аспектами.
0 голосов
/ 02 мая 2018

В дополнение к тому, что говорит @Bogdan, взгляните на CrudRepository или JpaRepository, это сэкономит вам много времени. Кроме того, по моему мнению, @Aspect классы помечены @Component, а не @Configuration.

...