This version is still in development and is not considered stable yet. For the latest stable version, please use Spring Framework 7.0.3!

Using JSR-330 Standard Annotations

Spring offers support for JSR-330 standard Dependency Injection annotations which are available in the jakarta.inject package. These annotations may optionally be used as alternatives to Spring annotations.

To use them, you need to have the relevant jar in your classpath. For example, the jakarta.inject artifact is available in the standard Maven repository (repo.maven.apache.org/maven2/jakarta/inject/jakarta.inject-api/2.0.0/),

If you use Maven, you can add the following dependency to your pom.xml file.

<dependency>
	<groupId>jakarta.inject</groupId>
	<artifactId>jakarta.inject-api</artifactId>
	<version>2.0.0</version>
</dependency>

Dependency Injection with @Inject and @Named

Instead of using @Autowired for dependency injection, you may optionally choose to use @jakarta.inject.Inject as follows.

  • Java

  • Kotlin

import jakarta.inject.Inject;

public class SimpleMovieLister {

	private MovieFinder movieFinder;

	@Inject
	public void setMovieFinder(MovieFinder movieFinder) {
		this.movieFinder = movieFinder;
	}

	public void listMovies() {
		this.movieFinder.findMovies(...);
		// ...
	}
}
import jakarta.inject.Inject

class SimpleMovieLister {

	@Inject
	lateinit var movieFinder: MovieFinder


	fun listMovies() {
		movieFinder.findMovies(...)
		// ...
	}
}

As with @Autowired, you can use @Inject at the field level, method level, and constructor-argument level.

Furthermore, as an alternative to Spring’s ObjectProvider mechanism, you may choose to declare your injection point as a jakarta.inject.Provider, allowing for on-demand access to beans of shorter scopes or lazy access to other beans through a Provider.get() call. The following example offers a variant of the preceding example.

  • Java

  • Kotlin

import jakarta.inject.Inject;
import jakarta.inject.Provider;

public class SimpleMovieLister {

	private Provider<MovieFinder> movieFinder;

	@Inject
	public void setMovieFinder(Provider<MovieFinder> movieFinder) {
		this.movieFinder = movieFinder;
	}

	public void listMovies() {
		this.movieFinder.get().findMovies(...);
		// ...
	}
}
import jakarta.inject.Inject
import jakarta.inject.Provider

class SimpleMovieLister {

	@Inject
	lateinit var movieFinder: Provider<MovieFinder>


	fun listMovies() {
		movieFinder.get().findMovies(...)
		// ...
	}
}

If you would like to use a qualified name for the dependency that should be injected, you may choose to use the @Named annotation as an alternative to Spring’s @Qualifier support, as the following example shows.

  • Java

  • Kotlin

import jakarta.inject.Inject;
import jakarta.inject.Named;

public class SimpleMovieLister {

	private MovieFinder movieFinder;

	@Inject
	public void setMovieFinder(@Named("main") MovieFinder movieFinder) {
		this.movieFinder = movieFinder;
	}

	// ...
}
import jakarta.inject.Inject
import jakarta.inject.Named

class SimpleMovieLister {

	private lateinit var movieFinder: MovieFinder

	@Inject
	fun setMovieFinder(@Named("main") movieFinder: MovieFinder) {
		this.movieFinder = movieFinder
	}

	// ...
}

As with @Autowired, @Inject can also be used with java.util.Optional or @Nullable. This is even more applicable here, since @Inject does not have a required attribute. The following examples show how to use @Inject with Optional, @Nullable, and Kotlin’s built-in support for nullable types.

import jakarta.inject.Inject;
import java.util.Optional;

public class SimpleMovieLister {

	@Inject
	public void setMovieFinder(Optional<MovieFinder> movieFinder) {
		// ...
	}
}
  • Java

  • Kotlin

import jakarta.inject.Inject;
import org.jspecify.annotations.Nullable;

public class SimpleMovieLister {

	@Inject
	public void setMovieFinder(@Nullable MovieFinder movieFinder) {
		// ...
	}
}
import jakarta.inject.Inject

class SimpleMovieLister {

	@Inject
	var movieFinder: MovieFinder? = null
}

@Named: Standard Equivalent to the @Component Annotation

Instead of @Component or other Spring stereotype annotations, you may optionally choose to use @jakarta.inject.Named, as the following example shows.

  • Java

  • Kotlin

import jakarta.inject.Inject;
import jakarta.inject.Named;

@Named("movieListener")
public class SimpleMovieLister {

	private MovieFinder movieFinder;

	@Inject
	public void setMovieFinder(MovieFinder movieFinder) {
		this.movieFinder = movieFinder;
	}

	// ...
}
import jakarta.inject.Inject
import jakarta.inject.Named

@Named("movieListener")
class SimpleMovieLister {

	@Inject
	lateinit var movieFinder: MovieFinder

	// ...
}

It is very common to use @Component or other Spring stereotype annotations without specifying an explicit name for the component, and @Named can be used in a similar fashion, as the following example shows.

  • Java

  • Kotlin

import jakarta.inject.Inject;
import jakarta.inject.Named;

@Named
public class SimpleMovieLister {

	private MovieFinder movieFinder;

	@Inject
	public void setMovieFinder(MovieFinder movieFinder) {
		this.movieFinder = movieFinder;
	}

	// ...
}
import jakarta.inject.Inject
import jakarta.inject.Named

@Named
class SimpleMovieLister {

	@Inject
	lateinit var movieFinder: MovieFinder

	// ...
}

When you use @Named, you can use component scanning in the exact same way as when you use Spring annotations, as the following example shows.

  • Java

  • Kotlin

@Configuration
@ComponentScan(basePackages = "org.example")
public class AppConfig  {
	// ...
}
@Configuration
@ComponentScan(basePackages = ["org.example"])
class AppConfig  {
	// ...
}
In contrast to @Component, the JSR-330 @Named annotation is not composable. You should use Spring’s stereotype model for building custom component annotations.

If you work with legacy systems that still use @javax.inject.Named or @javax.annotation.ManagedBean for components (note the javax package namespace), you can explicitly configure component scanning to include those annotations types, as shown in the following example.

  • Java

  • Kotlin

@Configuration
@ComponentScan(
	basePackages = "org.example",
	includeFilters = @Filter({
		javax.inject.Named.class,
		javax.annotation.ManagedBean.class
	})
)
public class AppConfig  {
	// ...
}
@Configuration
@ComponentScan(
	basePackages = ["org.example"],
	includeFilters = [Filter([
		javax.inject.Named::class,
		javax.annotation.ManagedBean::class
	])]
)
class AppConfig  {
	// ...
}

In addition, if you would like for the value attributes in @javax.inject.Named and @javax.annotation.ManagedBean to be used as component names, you need to override the isStereotypeWithNameValue(…​) method in AnnotationBeanNameGenerator to add explicit support for javax.annotation.ManagedBean and javax.inject.Named and register your custom AnnotationBeanNameGenerator via the nameGenerator attribute in @ComponentScan.

Limitations of JSR-330 Standard Annotations

When you work with JSR-330 standard annotations, you should know that some significant features are not available, as the following table shows.

Table 1. Spring component model versus JSR-330 variants
Spring JSR-330 JSR-330 restrictions / comments

@Autowired

@Inject

@Inject has no required attribute. Can be used with Java’s Optional instead.

@Component

@Named

JSR-330 does not provide a composable model, only a way to identify named components.

@Scope("singleton")

@Singleton

The JSR-330 default scope is like Spring’s prototype. However, in order to keep it consistent with Spring’s general defaults, a JSR-330 bean declared in the Spring container is a singleton by default. In order to use a scope other than singleton, you should use Spring’s @Scope annotation. jakarta.inject also provides a jakarta.inject.Scope annotation; however, this one is only intended to be used for creating custom annotations.

@Qualifier

@Qualifier / @Named

jakarta.inject.Qualifier is just a meta-annotation for building custom qualifiers. Concrete String qualifiers (like Spring’s @Qualifier with a value) can be associated through jakarta.inject.Named.

@Value

-

no equivalent

@Lazy

-

no equivalent

ObjectFactory

Provider

jakarta.inject.Provider is a direct alternative to Spring’s ObjectFactory, only with a shorter get() method name. It can also be used in combination with Spring’s @Autowired or with non-annotated constructors and setter methods.