简体   繁体   中英

Spring CGLib proxy - class variables become null

I have a filter service whose methods are profiled through the aspect. As an example I will give you a piece of code where I have a problem

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

As i know, by default, If the class does not inherit the interface with at least one method, the CGlib proxy will be used and Cglib works through inheritance.
The problem is this: when I call the filterItems method from the controller, the debugger shows in this method that this - FilterService .
Further in this method another method of this class which too should be profiled is caused. In order for the proxy to work, I need self autowired. After that I called my method via self.initNonSpecificFilters and in the debugger I already see that this - FilterService$$EnhancerBySpringCGLIB and all my variables in my class is null, so I get null pointer exception.

Why so, if CGLIb seems to work through inheritance? And why in the first method(filterItems) this - was a class without CGlib, but when you call from it another method (filterItems -> initNotSpecificFilters), cglib already appears.

The problem is that dynamic proxies, no matter whether JDK interface proxies or CGLIB class proxies, only inherit

  • public methods (JDK, CGLIB) or
  • protected and package-scoped methods (CGLIB only).

Furthermore, proxies do not inherit any instance variable values because that is not their purpose, they only wrap around methods and call the originals plus maybe before and after aspect advices or interceptors.

Now your situation is as follows:

  • Your method initNonSpecificFilters(..) is private. Ie if you call it upon self , you will actually still call the original method (because it is not wrapped), but the proxy's members have no values, of course.

  • BTW, the fact that the method is private is also why the Spring AOP aspect would not kick in for that method if you had a pointcut targeting it (with AspectJ it would be different).

Search the Spring manual for the term self-invocation , the behaviour is nicely documented.

The solution to your problem is to make the method non-private.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM