<h2>The problem:</h2>
<p>The problem appears in a k8s pod running spring-boot, java 8 (more details below)</p>
<p>When using <code>ObjectProvider&lt;&gt;</code> and calling <code>*provider.getObject(.....)*</code>,  on
a prototype bean defined in Spring Configuration, every now and then (never
find a way to make it happen regularly) setter injection methods are not called.</p>
<p><strong>Update oct, 2:</strong> See <a href="https://github.com/spring-projects/spring-framework/issues/25840" rel="nofollow noreferrer">Spring Issue #25840</a></p>
<p>Most of the time this works perfectly well, but sometimes, it constructs a new object
but misses to call the @Autowired setter method (checked with log information).</p>
<p>We also discover that 90% of the time it happens after application startup, but not always.</p>
<p><strong>UPDATE sept, 21</strong>: Deleting (Restarting) de pod solves the problem.</p>
<p><strong>UPDATE sept, 22</strong>: Once it happens it will happen all the time, I mean is not that it fails once, and the next time it works ok, it will always fail to call setters.</p>
<p><strong>UPDATE sept, 23</strong>: New evidence related to concurrency problem in the real application, didn't appear until now, a single thread alone seemed
to generate the problem. (take a look at classes below to understand better
this description)</p>
<p><strong>ToipParentClass</strong> (this is a Strategy Implementation) has setter @Autowired for</p>
<ul>
<li>VlocityService</li>
<li>OrderManagemenService</li>
</ul>
<p><strong>InternetParentClass</strong> (this is a Strategy Implementation) has setter @Autowired for</p>
<ul>
<li>VlocityService</li>
<li>OrderManagemenService</li>
</ul>
<p><strong>Log (commented)</strong></p>
<pre><code>[-nio-80-exec-10] GuidTaskController   : Build Strategy using XOM_TOIP_OFFER .                    
[p-nio-80-exec-2] GuidTaskController   : Build Strategy using XOM_INTERNET_OFFER .                    
[-nio-80-exec-10] ToipParentClass      : @Constructing ToipParentClass                                             
[p-nio-80-exec-2] InternetParentClass  : @Constructing InternetParentClass                                         
[-nio-80-exec-10] ToipParentClass      : @Autowiring VlocityServices@7951cd46                                      
[p-nio-80-exec-2] InternetParentClass  : @Autowiring VlocityServices@7951cd46                                      
[-nio-80-exec-10] ToipParentClass      : @Autowiring OrderManagementService@3385326a     
-------------------------------------------------------------
ERROR !!! Missing @Autowiring log  
[p-nio-80-exec-2] InternetParentClass  : @Autowiring OrderManagementService@7951cd46                      
-------------------------------------------------------------
[p-nio-80-exec-2] Controller           : Unexpected Error
2020-09-22T18:56:45.544525916Z
-------------------------------------------------------------
ERROR: NullPointer when using not set OrderManagementService
-------------------------------------------------------------
2020-09-22T18:56:45.544530395Z java.lang.NullPointerException: null
2020-09-22T18:56:45.544534074Z  at InternetParentClass.generateIds(InternetParentClass.java:50) ~[classes!/:BUG001_PrototypeBeanAutowired-8]                                       
2020-09-22T18:56:45.544538568Z  at GuidTaskController.setGUID(GuidTaskController.java:180) ~[classes!/:BUG001_PrototypeBeanAutowired-8]
</code></pre>
<p>I made a simple test in <a href="https://github.com/toniocus/strategy-calculator" rel="nofollow noreferrer">https://github.com/toniocus/strategy-calculator</a> run it standalone, different jdk8 versions, also in the same docker image used in the pod (all things in the project), and failed to make it FAIL.</p>
<p>Any ideas on where to look for a problem, suggestions on what to try, or even
a solution :-),  will be greatly welcome, thanks in advance</p>
<p>Below the product versions, classes.</p>
<h2>Detail about versions:</h2>
<p><strong>k8s:</strong></p>
<pre><code>v1.14.9-eks-658790
</code></pre>
<p><strong>spring-boot:</strong></p>
<pre><code>2.1.4.RELEASE
</code></pre>
<p><strong>JDK:</strong></p>
<pre><code>  openjdk version &quot;1.8.0_212&quot;
  OpenJDK Runtime Environment (IcedTea 3.12.0) (Alpine 8.212.04-r0)
  OpenJDK 64-Bit Server VM (build 25.212-b04, mixed mode)
</code></pre>
<h2>The Classes</h2>
<p>A snippet on the classes involved, no real code, do not worry about syntax errors.
(real code can be found in <a href="https://github.com/toniocus/strategy-calculator" rel="nofollow noreferrer">https://github.com/toniocus/strategy-calculator</a>)</p>
<pre><code>// ============================================================
public interface Strategy {
   void work(...);
}

// ============================================================
@Service
public class Service {
    public void doSomething() {
       ......
       ......
    }
}

// ============================================================
public class MobileStrategy implements Strategy {
   private Service service;

   @Autowired
   public void setService(Service s) {
       this.service = s;   // setter not called every now and then
   }



   public void work(...) {
       this.service.doSomething();  // throws NullPointerException every now an then
   }
}

// ============================================================
public enum StrategyEnum {

    MOBILE(&quot;mobileKey&quot;, MobileStrategy.class),
    TV(&quot;tvKey&quot;, TvStrategy.class),
    .......

    public Class&lt;Strategy&gt; getImplementationClass() {
       ......
    }

    public StrategyEnum findByKey(String key) {
       .....
    }
}

// ============================================================
@Configuration
public class Configuration {

    @Bean
    @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public Strategy getStrategy(final StrategyEnum selectorEnum) {

        try {

            Constructor&lt;? extends Strategy&gt; constructor =
                    selectorEnum.getImplementationClass().getConstructor();

            return constructor.newInstance();
        }
        catch (Exception ex) {

            throw new Exception(&quot;Not able to instantiate interface implementation&quot;
                    + &quot; for enum: &quot; + selectorEnum
                    , ex);
        }

    }
}


// ============================================================
@RestController
public class MathOperRestController {

    @Autowired
    ObjectProvider&lt;Strategy&gt; provider;

    @GetMapping(&quot;/{operation}/{x}/{y}&quot;)
    public BigDecimal add(
            @PathVariable(&quot;operation&quot;) final String operation
            , @PathVariable(&quot;x&quot;) final BigDecimal x
            , @PathVariable(&quot;y&quot;) final BigDecimal y
            ) {

        Strategy strategy = this.provider.getObject(StrategyEnum.findByKey(operation));
        strategy.doWork(x, y);

        return BigDecimal.ZERO;
    }
</code></pre>
<p><strong>UPDATE sept,21</strong> added Service class to samples</p>

<h2>The problem I found</h2>
<p><strong>Update oct, 1:</strong> Please read @Denium comment in the question !!!! (thanks for it).</p>
<p>After today's (Sept, 23) update, seems clearly the problem is a concurrency problem, I was able to reproduce it easily (See <a href="https://github.com/toniocus/strategy-calculator/blob/master/src/test/java/ar/com/exeo/calc/SimpleSpringAppTest.java" rel="nofollow noreferrer">SimpleSpringAppTest.java</a>)
in a Simple Spring app, no spring-boot.</p>
<p>Made all Strategy implementations have the same set of @Autowired setters
and the error is still there.</p>
<p>Seems there is some caching done, and @Autowired setters are taken from the cache, and not from the newly constructed object, although I try to dig into spring sources difficult to understand in so short time.</p>
<p>The problem was solved, avoiding concurrency (changes below), so now my question:</p>
<p><strong>Is this the expected behaviour or is it a bug ?</strong></p>
<p>I was not able to find any documentation regarding this problem or describing this behaviour anywhere, so still a question for me.</p>
<p>I tested in spring-boot versions 1.5.22, 2.1.4 (what we are currently using), and 2.3.4 and in all cases the same problem appears, just in a simple spring application, no need of RestController or so.</p>
<h2>Workaround 1</h2>
<p>Add an intermediate Factory to ensure Strategy beans are created 'synchronously'.</p>
<p><strong>Update oct, 1:</strong> After @Deinum comments, from what I understood, Spring will be scanning classes every time (or almost every time) for annotations, so I guess Workaround 2 is probably a better solution.</p>
<p>This solution is more suitable for my current environment.</p>
<h3>New Class StrategyFactory</h3>
<p>Note the <code>getStrategy(...)</code> method is synchronized, I guess this solution
will have some performance impact, but still not able to measure it.</p>
<pre><code>@Component
public class StrategyFactory {

    @Autowired
    ObjectProvider&lt;Strategy&gt; provider;

    public synchronized Strategy getStrategy(final MathOperEnum operation) {
        return this.provider.getObject(operation);
    }

}
</code></pre>
<h3>Changes in RestController</h3>
<p>Now using the StrategyFactory instead of the ObjectProvider</p>
<pre><code>@RestController
public class MathOperRestController {

    @Autowired
    StrategyFactory factory;

    @GetMapping(&quot;/{operation}/{x}/{y}&quot;)
    public BigDecimal add(
            @PathVariable(&quot;operation&quot;) final String operation
            , @PathVariable(&quot;x&quot;) final BigDecimal x
            , @PathVariable(&quot;y&quot;) final BigDecimal y
            ) {

        Strategy strategy = this.factory
             .getStrategy(StrategyEnum.findByKey(operation));

        strategy.doWork(x, y);

        return BigDecimal.ZERO;
    }
}
</code></pre>
<h2>Workaround 2</h2>
<ul>
<li>Make the StrategyFactory ApplicationContextAware</li>
<li>Add @Componente/@Scope annotation to each strategy implementation</li>
<li>Remove @Configuration class</li>
</ul>
<pre><code>@Component
public class StrategyFactory implements ApplicationContextAware {

    private ApplicationContext ctx;


    public Strategy getStrategy(final StrategyEnum operation) {
        return this.ctx.getBean(
               operation.getImplementationClass()
               );
    }


    @Override
    public void setApplicationContext(
         final ApplicationContext applicationContext) 
    throws BeansException {

        this.ctx = applicationContext;

    }

}
</code></pre>
