Class PythonPooledInstance

java.lang.Object
io.micronaut.context.python.PythonPooledInstance

@Internal public final class PythonPooledInstance extends Object
The per-context Python instances of one pooled bean that has constructor arguments.

A pooled bean without arguments needs none of this: the pool caches one instance per context per class, because every such bean of a given class is interchangeable. Arguments break that. @ContextPooled is prototype scoped, so two beans of the same class can hold different dependencies — a different qualifier, or a prototype dependency — and a cache keyed by class alone would hand the first bean's instance to the second, with the wrong dependencies and no error.

So the instances belong to the bean rather than to the pool -- keeping them in the pool would accumulate entries for prototype beans long since collected, which on a long-running server is an unbounded leak.

Their lifetime needs both halves, and neither works alone, because the references run in both directions. A stored instance reaches this holder: the host-object back-reference points at the wrapper, and the wrapper holds the holder. This holder reaches every context it has served, because a Value holds its own Context. So a weak key never fires, whichever way round the map is: the value in the entry keeps the key reachable.

The map therefore lives here, which is what makes a collected bean take its instances with it, and each context keeps a weak set of the holders it has served so that closing it can call forget(Context). A closed context is removed from every holder that served it; a collected holder takes its whole map at once.

Since:
5.2.10
  • Constructor Details

  • Method Details

    • producedBy

      public static PythonPooledInstance producedBy(String displayName, Function<org.graalvm.polyglot.Context, org.graalvm.polyglot.Value> valueFactory)
      A holder whose value for each context is built by the given function.

      For an AOP-proxied pooled bean. A Python proxy belongs to the context it was created in, so one proxy cannot serve a pooled bean; the function creates a proxy in whichever context asks, and they are cached here like any other per-context value.

      Parameters:
      displayName - What to call the bean in a diagnostic
      valueFactory - Builds the value for a context
      Returns:
      A holder backed by that function
    • seeded

      public static PythonPooledInstance seeded(PythonContextRuntime.PythonClassReference classReference, org.graalvm.polyglot.Value existing)
      A holder seeded with an instance that already exists in a context.

      Used for the wrapper of an AOP proxy target. The proxy is a Python object created for one context and handed to Java to be wrapped, so the wrapper stands for that object in that context. It carries no constructor arguments, because the proxy is not built from them, so it cannot materialise in a different context -- and it is not asked to: a proxy belongs to the context it was created for.

      Parameters:
      classReference - The Python class
      existing - The instance, belonging to the context it came from
      Returns:
      A holder of that instance
    • classReference

      Returns:
      The Python class these instances are of, or null for a factory-built holder
    • in

      public org.graalvm.polyglot.Value in(org.graalvm.polyglot.Context context)
      This bean's instance in the given context, constructing it there on first use.

      Construction runs before the value is published, and holds nothing while it runs. Guest code must not run under a lock the runtime might need: Python re-entering for the same bean would wait on the thread holding it, which is itself waiting on the interpreter lock. A duplicate construction is cheaper than that, and the loser is discarded.

      Parameters:
      context - The context
      Returns:
      The instance belonging to that context