micronaut-projects / micronaut-core

Micronaut Application Framework
http://micronaut.io
Apache License 2.0
6.07k stars 1.07k forks source link

Register beans with external annotations (aka package level or mixin annotations) #1885

Open agentgt opened 5 years ago

agentgt commented 5 years ago

(I asked on gitter if it was alright to file an issue about this. Here is the comment thread: https://gitter.im/micronautfw/questions?at=5d25f4a417cc7b05caa55674).

Currently to register a bean for creation in Micronaut you have roughly three choices:

  1. Use a javax.injection annotation directly on the bean (e.g. @Singleton)
  2. Use a @Factory and manually wire up the bean
  3. ApplicationContext#registerSingleton but that requires the bean already be instantiated.

In our code base that used Spring we leveraged Spring XML to wire beans that have a single constructor with all of its collaborators as arguments aka constructor based injection. Those collaborators are private final and thus the bean cannot be created with a default constructor (for the most part).

In Spring XML (since Spring 2) you can list the beans in whatever order like:

<bean class="my.package.SomeClass" /> <!-- no need to list args -->
<bean class="my.package.SomeOtherClassMayDependOnSomeClass" />

Spring will automatically wire up the beans.

For various reasons we did not use @Inject as @Inject while not as bad as @Autowire still required a dependency. Furthermore putting @Inject (and friends) on a bean sort of violates the single responsibility in that the class now knows its going to be used by dependency injection but I understand how many could see that as a weak argument. (Also back in the day annotation registration was slow for Spring so just listing all the beans in XML was faster but that is a moot point with micronaut).

Anyway we are migrating from Spring to Micronaut and now I have the choice of littering all of our classes with @Singleton or doing tedious instantiating of the beans in a @Factory which requires me to manually fill each constructor.

Thus what I'm proposing is to allow registration of beans with out requiring annotations directly on the bean. This could be a package level annotation (package-info.java) or some configuration class. Another approach is similar to what Jackson does: https://github.com/FasterXML/jackson-docs/wiki/JacksonMixInAnnotations but probably don't need that level of configuration like Jackson does.

I understand that there are pitfalls to this approach in that if the beans come from other pre-compiled projects they will need to have the annotation processors run on them prior and thus would require me to put the list of all beans for each project in some package level annotation but this would only require one file change for each project instead of changing each class (to add @Singleton).

graemerocher commented 5 years ago

Probably possible, we already have something similar with bean introspections with @Introspected(packages="foo.bar") which will import introspections from the given package