首页 > 解决方案 > Spring CGLib 代理 - 类变量变为空

问题描述

我有一个过滤器服务,其方法通过方面进行分析。作为一个例子,我会给你一段我有问题的代码

    @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调用了我的方法,在调试器中我已经看到了这个- FilterService$$EnhancerBySpringCGLIB我的类中的所有变量都是空的,所以我得到空指针异常。

如果 CGLIb 似乎通过继承工作,为什么会这样?以及为什么在第一个方法(filterItems)中这个- 是一个没有 CGlib 的类,但是当你从它调用另一个方法(filterItems -> initNotSpecificFilters)时,cglib 已经出现了。

标签: javaspring-aopcglibaspect

解决方案


问题是动态代理,不管是JDK接口代理还是CGLIB类代理,都只能继承

  • 公共方法(JDK、CGLIB)或
  • 受保护的和包范围的方法(仅限 CGLIB)。

此外,代理不继承任何实例变量值,因为这不是它们的目的,它们只包装方法并调用原始方法,并可能在方面建议或拦截器之前和之后调用。

现在你的情况如下:

  • 您的方法initNonSpecificFilters(..)是私有的。也就是说,如果你调用它self,你实际上仍然会调用原始方法(因为它没有被包装),但是代理的成员当然没有值。

  • 顺便说一句,该方法是私有的这一事实也是为什么如果您有一个针对该方法的切入点,则 Spring AOP 方面不会为该方法启动(使用 AspectJ 会有所不同)。

在Spring 手册中搜索术语self-invocation,该行为有很好的记录。

您的问题的解决方案是使该方法成为非私有方法。


推荐阅读