CDI deployment is quite automatic. Either you use a beans.xml and the scanning of the archive is forced but you still scan the whole "jar" or you don't have a beans.xml and you scan it with default rules.

This is not a bad default because it is "working by default" but it also makes quite hard to know what is scanned out of the box.

Why should you care? Scanning control, even if not portable, is a key of the usability of CDI based applications - in EE or not. If not tuned and the application has a real stack then you will scan a bunch of useless jars and slow down the bootstrap of your application. Why do we care? Just cause it makes development iterations slower for no reasons! In other words: controlling its scanning ensure development stays smooth and fast.

There are multiple ways to configure the scanning but let see one procedure you can use with TomEE without requiring any "guess" logic.

Find the CDI beans to filter them

The first step is to find which beans are deployed. To do that you can write a custom extension or just use TomEE  openejb.cdi.debug options. To activate it just add it in the container or JVM system properties:

openejb.cdi.debug=true

This will simply log all classes keep as potentially CDI beans (ie before effectively starting CDI container). Output will look like:

INFOS - Existing thread singleton service in SystemInstance(): org.apache.openejb.cdi.ThreadSingletonServiceImpl@78aa1f72
INFOS - OpenWebBeans Container is starting...
INFOS - Adding OpenWebBeansPlugin : [CdiPlugin]
INFOS - Using annotated mode for file:/media/data/dev/github/rblog/target/test-classes/ looking all classes to find CDI beans, maybe think to add a beans.xml if not there or add the jar to exclusions.list
INFOS - CDI beans for rblog
INFOS -     com.github.rmannibucau.rblog.angular2.UrlRewriting
INFOS -     com.github.rmannibucau.rblog.configuration.Configuration
INFOS -     com.github.rmannibucau.rblog.configuration.ConfigurationProducer
INFOS -     com.github.rmannibucau.rblog.configuration.ConfigurationProducer$Decrypter
INFOS -     com.github.rmannibucau.rblog.configuration.DefaultDecrypter
INFOS -     com.github.rmannibucau.rblog.event.DoBackup
INFOS -     com.github.rmannibucau.rblog.jaxrs.AttachmentResource
INFOS -     com.github.rmannibucau.rblog.jaxrs.BackupResource
INFOS -     com.github.rmannibucau.rblog.jaxrs.BackupResource$1
INFOS -     com.github.rmannibucau.rblog.jaxrs.BitlyResource
INFOS -     com.github.rmannibucau.rblog.jaxrs.BitlyResource$State
INFOS -     com.github.rmannibucau.rblog.jaxrs.BitlyResource$Url
INFOS -     com.github.rmannibucau.rblog.jaxrs.CategoryResource
INFOS -     com.github.rmannibucau.rblog.jaxrs.PostResource
INFOS -     com.github.rmannibucau.rblog.jaxrs.RBlogApplication
INFOS -     com.github.rmannibucau.rblog.jaxrs.RBlogConfiguration
INFOS -     com.github.rmannibucau.rblog.jaxrs.RBlogConfiguration$Configuration
INFOS -     com.github.rmannibucau.rblog.jaxrs.RssResource
INFOS -     com.github.rmannibucau.rblog.jaxrs.RssResource$AtomLink
INFOS -     com.github.rmannibucau.rblog.jaxrs.RssResource$Channel
INFOS -     com.github.rmannibucau.rblog.jaxrs.RssResource$Guid
INFOS -     com.github.rmannibucau.rblog.jaxrs.RssResource$Item
INFOS -     com.github.rmannibucau.rblog.jaxrs.RssResource$Rss
INFOS -     com.github.rmannibucau.rblog.jaxrs.SiteMapResource
INFOS -     com.github.rmannibucau.rblog.jaxrs.SiteMapResource$1
INFOS -     com.github.rmannibucau.rblog.jaxrs.SiteMapResource$TChangeFreq
INFOS -     com.github.rmannibucau.rblog.jaxrs.SiteMapResource$TUrl
INFOS -     com.github.rmannibucau.rblog.jaxrs.SiteMapResource$Urlset
INFOS -     com.github.rmannibucau.rblog.jaxrs.UserResource
INFOS -     com.github.rmannibucau.rblog.jaxrs.async.Async
INFOS -     com.github.rmannibucau.rblog.jaxrs.async.AsyncInterceptor
INFOS -     com.github.rmannibucau.rblog.jaxrs.async.AsyncInterceptor$Meta
INFOS -     com.github.rmannibucau.rblog.jaxrs.async.AsyncInterceptor$Metas
INFOS -     com.github.rmannibucau.rblog.jaxrs.async.AsyncInterceptor$NoContentHandlerAsyncResponse
INFOS -     com.github.rmannibucau.rblog.jaxrs.async.AsyncInterceptor$TransactionProvider
INFOS -     com.github.rmannibucau.rblog.jaxrs.dump.VisitorSupport
INFOS -     com.github.rmannibucau.rblog.jaxrs.format.JSDateConverter
INFOS -     com.github.rmannibucau.rblog.jaxrs.model.AttachmentModel
INFOS -     com.github.rmannibucau.rblog.jaxrs.model.AttachmentPage
INFOS -     com.github.rmannibucau.rblog.jaxrs.model.CategoryModel
INFOS -     com.github.rmannibucau.rblog.jaxrs.model.Message
INFOS -     com.github.rmannibucau.rblog.jaxrs.model.NotificationModel
INFOS -     com.github.rmannibucau.rblog.jaxrs.model.PostModel
INFOS -     com.github.rmannibucau.rblog.jaxrs.model.PostPage
INFOS -     com.github.rmannibucau.rblog.jaxrs.model.TopPosts
INFOS -     com.github.rmannibucau.rblog.jaxrs.model.TopPosts$CategoryData
INFOS -     com.github.rmannibucau.rblog.jaxrs.model.UserModel
INFOS -     com.github.rmannibucau.rblog.jaxrs.package-info
INFOS -     com.github.rmannibucau.rblog.jaxrs.provider.AccessDeniedExceptionExceptionMapper
INFOS -     com.github.rmannibucau.rblog.jaxrs.provider.EntityConcurrentModificationException
INFOS -     com.github.rmannibucau.rblog.jaxrs.provider.EntityConcurrentModificationExceptionExceptionMapper
INFOS -     com.github.rmannibucau.rblog.jaxrs.provider.JSonProvider
INFOS -     com.github.rmannibucau.rblog.jaxrs.provider.TransactionExceptionExceptionMapper
INFOS -     com.github.rmannibucau.rblog.jaxrs.reflect.CollectionType
INFOS -     com.github.rmannibucau.rblog.jpa.Attachment
INFOS -     com.github.rmannibucau.rblog.jpa.BaseEntity
INFOS -     com.github.rmannibucau.rblog.jpa.Category
INFOS -     com.github.rmannibucau.rblog.jpa.Notification
INFOS -     com.github.rmannibucau.rblog.jpa.Notification$State
INFOS -     com.github.rmannibucau.rblog.jpa.Post
INFOS -     com.github.rmannibucau.rblog.jpa.PostType
INFOS -     com.github.rmannibucau.rblog.jpa.Token
INFOS -     com.github.rmannibucau.rblog.jpa.User
INFOS -     com.github.rmannibucau.rblog.lang.Exceptions
INFOS -     com.github.rmannibucau.rblog.lang.JaxRsPromise
INFOS -     com.github.rmannibucau.rblog.lang.JaxRsPromise$PromiseInvocationCallback
INFOS -     com.github.rmannibucau.rblog.security.TokenPrincipal
INFOS -     com.github.rmannibucau.rblog.security.cdi.AccessDeniedException
INFOS -     com.github.rmannibucau.rblog.security.cdi.Logged
INFOS -     com.github.rmannibucau.rblog.security.cdi.LoggedInterceptor
INFOS -     com.github.rmannibucau.rblog.security.service.TokenGenerator
INFOS -     com.github.rmannibucau.rblog.security.web.InvalidCredentialsException
INFOS -     com.github.rmannibucau.rblog.security.web.InvalidCredentialsExceptionExceptionMapper
INFOS -     com.github.rmannibucau.rblog.security.web.SecurityFilter
INFOS -     com.github.rmannibucau.rblog.security.web.SecurityFilter$1
INFOS -     com.github.rmannibucau.rblog.security.web.SecurityFilter$TokenUpdater
INFOS -     com.github.rmannibucau.rblog.security.web.TokenResource
INFOS -     com.github.rmannibucau.rblog.security.web.model.Credentials
INFOS -     com.github.rmannibucau.rblog.security.web.model.TokenError
INFOS -     com.github.rmannibucau.rblog.security.web.model.TokenValue
INFOS -     com.github.rmannibucau.rblog.service.Backup
INFOS -     com.github.rmannibucau.rblog.service.Backup$Internal
INFOS -     com.github.rmannibucau.rblog.service.Backup$Internal$1
INFOS -     com.github.rmannibucau.rblog.service.BitlyService
INFOS -     com.github.rmannibucau.rblog.service.BitlyService$BitlyData
INFOS -     com.github.rmannibucau.rblog.service.BitlyService$BitlyResponse
INFOS -     com.github.rmannibucau.rblog.service.IOService
INFOS -     com.github.rmannibucau.rblog.service.PasswordService
INFOS -     com.github.rmannibucau.rblog.service.SlugService
INFOS -     com.github.rmannibucau.rblog.service.TokenEviction
INFOS -     com.github.rmannibucau.rblog.service.URLService
INFOS -     com.github.rmannibucau.rblog.setup.AnalyticsConfiguration
INFOS -     com.github.rmannibucau.rblog.setup.DefaultUser
INFOS -     com.github.rmannibucau.rblog.setup.PersistenceConfiguration
INFOS -     com.github.rmannibucau.rblog.social.SocialNotifier
INFOS -     com.github.rmannibucau.rblog.social.SocialNotifier$NotifierStates
INFOS -     com.github.rmannibucau.rblog.social.SocialService
INFOS -     com.github.rmannibucau.rblog.social.TwitterService
INFOS -     com.github.rmannibucau.rblog.social.TwitterService$NonceProvider
INFOS -     com.github.rmannibucau.rblog.social.TwitterService$TimestampProvider
INFOS -     com.github.rmannibucau.rblog.test.BitlyMocks
INFOS -     com.github.rmannibucau.rblog.test.TwitterMocks
INFOS -     com.github.rmannibucau.rblog.test.TwitterMocks$NonceTestProvider
INFOS -     com.github.rmannibucau.rblog.test.TwitterMocks$TimestampTestProvider
INFOS -     org.apache.openejb.cdi.transactional.MandatoryInterceptor
INFOS -     org.apache.openejb.cdi.transactional.NeverInterceptor
INFOS -     org.apache.openejb.cdi.transactional.NotSupportedInterceptor
INFOS -     org.apache.openejb.cdi.transactional.RequiredInterceptor
INFOS -     org.apache.openejb.cdi.transactional.RequiredNewInterceptor
INFOS -     org.apache.openejb.cdi.transactional.SupportsInterceptor

The interesting lines are after:

INFOS - CDI beans for rblog

What does it give us? The list of scanned classes. Idea is to extract all classes which are not CDI beans and configure the container to exclude them from the scanning. With TomEE it leads to use exclusions.list to exclude a full jar (if you see commons-* or bouncycastle scanned for instance) or scan.xml to exclude a package or classes from a module without excluding the full jar (common if you want to scan 2 classes over 1000 for a particular jar). You can also use CDI standard exclusions in beans.xml but it generally happens a bit later so this is more a business exclusion than a scanning exclusion (= less impacting on the startup duration).

Concretely once well configured you should only scan your business beans. This will ensure the container starts as fast as possible and you control the CDI context (note that a side effect is you can also remove some ambiguity in the resolution).

When to do it?

Ideally each time you add a dependency to your project. TomEE - and other servers - comes with different strategies and a set of default exclusions of well known dependencies. It is better to ensure you don't rely too much on the defaults quality and ensure it actually fits your use case to validate what the container does for you at least once per project/container-dependency upgrade. Said otherwise: checking instead of assuming should be the rule.

In practise you can accept to scan small libraries, it will be fast but big ones will be impacting and therefore need to be excluded if not participating to CDI directly. This "rule" is probably the best I can recommand you in a generic manner but it omits what means "big". It depends the computer(s) you use and your stack/development model. Best there is to do the test on 1 or 2 projects and get your own metric(s) for that definition.

What if my container doesn't provide me that information that smoothly?

There are a lot of alternatives:

  • start from excluding 3rd party libraries (full jars) which are not CDI libraries or not used like that
  • if not enough, configure packages (often companies have a dedicated package - com.company.application - which works well if configured as inclusion)
  • write a small extension capturing ProcessAnnotationType event and listing all types from there. It is not the full set of scanned classes but generally it is good enough to configure the scanning
  • For weld based containers, give a try to probe webapp which can help. It is more impacting in term of setup but a way to get a good information level without redeveloping something new yourself

Conclusion

Scanning is a critical part of the setup of a project which is also a living part of it. Badly setup you can end up loosing several minutes to boot a container which would only require few seconds once configured. This is not something you should put in a backlog but solve upfront to enable your team to be productive!

From the same author:

In the same category: