Spring CGLib proxy - переменные класса обнуляются - PullRequest
0 голосов
/ 31 мая 2018

У меня есть служба фильтрации, методы которой представлены в аспекте.В качестве примера я приведу фрагмент кода, в котором у меня есть проблема

    @Service
    public class FilterService extends AbstractService {
        private static final Logger log = LoggerFactory.getLogger(FilterService.class);

        @Autowired
        //Proxy to profiling class
        private FilterService self;

        private final ItemsRepository itemsRepository;
        private final Map<String, EnumFilter> enumFilters;

        public FilterService(ReadWriteLock readWriteLock,
                             ItemsRepository itemsRepository,
                             CategoryRepository categoryRepository, ItemsMapper itemsMapper,
                             CharacteristicsRepository characteristicsRepository,
                             List<EnumFilter> enumFilters) {
            super(readWriteLock.readLock());
            this.itemsRepository = itemsRepository;
            this.enumFilters = enumFilters.stream().collect(Collectors.toMap(EnumFilter::getId, y -> y));
        }

        @Profileable
        public ItemsViewShared filterItems(@Nullable String categoryId,
                                           @NotNull Set<String> ids,
                                           @NotNull Lang lang,
                                           @NotNull SortType sortType,
                                           @NotNull FilterInfo filterInfo) {
            try {
                this.readLock.lock();
                final ItemsViewShared itemsViewResponse = new ItemsViewShared(); //in this line inspector show this = FilterService

                List<Filter> allFilters = self.initNonSpecificFilters(lang, filterInfo); //problem is here
      //some code...

    @Profileable
    private List<Filter> initNonSpecificFilters(@NotNull Lang lang, @NotNull FilterInfo filterInfo) {
        final List<NumericFilter> allNumericNonSpecific = NumericFilter.getAllNonSpecific(lang, filterInfo);

       //in this line enumFilters - null
        final List<EnumOptionFilter> allEnumNonSpecific = enumFilters.values().stream()
                .flatMap(x -> x.getAllOptions(lang, filterInfo).stream())
                .collect(Collectors.toList());

Как я знаю, по умолчанию, если класс не наследует интерфейс хотя бы с одним методом, прокси CGlibи Cglib работает через наследование.
Проблема заключается в следующем: когда я вызываю метод filterItems из контроллера, отладчик показывает в этом методе, что this - FilterService .
Далее в этом методе вызывается другой метод этого класса, который тоже должен быть профилирован.Для того, чтобы прокси работал, мне нужно самостоятельно подключиться.После этого я вызвал мой метод через self.initNonSpecificFilters , и в отладчике я уже вижу, что this - FilterService $$ EnhancerBySpringCGLIB и все мои переменные в моем классе - этоnull, поэтому я получаю исключение нулевого указателя.

Почему так, если CGLIb работает через наследование?И почему в первом методе (filterItems) этот - был классом без CGlib, но когда вы вызываете из него другой метод (filterItems -> initNotSpecificFilters), уже появляется cglib.

1 Ответ

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

Проблема заключается в том, что динамические прокси, независимо от того, являются ли прокси интерфейса JDK или прокси класса CGLIB, наследуют только

  • открытых методов (JDK, CGLIB) или
  • защищенных и пакетныхметоды с областью действия (только CGLIB).

Кроме того, прокси-серверы не наследуют никаких значений переменных экземпляра, потому что это не является их целью, они только оборачивают методы и вызывают оригиналы плюс, возможно, до и после советов по аспектам илиперехватчики.

Теперь ваша ситуация выглядит следующим образом:

  • Ваш метод initNonSpecificFilters(..) является конфиденциальным.Т.е. если вы вызовете его при self, вы все равно будете вызывать оригинальный метод (потому что он не упакован), но члены прокси-сервера, разумеется, не имеют значений.

  • Кстатитот факт, что метод является закрытым, также является причиной того, что аспект Spring AOP не будет задействован для этого метода, если у вас есть нацеленный на него pointcut (с AspectJ он будет другим).

Найдите в руководстве Spring термин self-invocation , поведение хорошо документировано.

Решение вашей проблемы - сделать метод не закрытым.

...