Routing
Routing in webforJ with Spring works exactly the same way as in plain webforJ applications. You still use the @Route
annotation to define routes, the same navigation patterns, and the same route lifecycle. The only difference is that when Spring is present, your routes can also receive Spring beans through constructor injection.
When you navigate to a route, webforJ creates the route instance - but with Spring on the classpath, it uses Spring's container to resolve dependencies. This means your routes can use the full power of Spring's ecosystem (services, repositories, custom beans) while maintaining the familiar webforJ routing behavior.
For a comprehensive understanding of dependency injection patterns and Spring's IoC container, see Spring's official dependency injection documentation.
How webforJ creates routes with Spring
webforJ handles route creation differently when Spring is present. The framework's object creation mechanism detects Spring Boot on the classpath and delegates to Spring's AutowireCapableBeanFactory
for creating instances with dependency injection.
For classes discovered through @Routify
scanning, webforJ always creates fresh instances and never reuses existing Spring beans. Each user navigation receives a clean route instance with no shared state. The creation process:
- User navigates to a route
- webforJ requests a new instance (ignoring any existing Spring bean definitions)
- Spring's factory creates the instance and injects constructor dependencies
- The route initializes with all dependencies satisfied
This behavior is intentional and differs from typical Spring beans. Even if you register a route as a Spring bean with @Component
, webforJ ignores that bean definition and creates a fresh instance for each navigation.
Using Spring beans in routes
Your route classes don't require Spring annotations. The @Route
annotation alone enables both route discovery and dependency injection:
@Route("/dashboard")
public class DashboardView extends Composite<Div> {
private final MetricsService metricsService;
private final UserRepository userRepository;
public DashboardView(MetricsService metricsService, UserRepository userRepository) {
this.metricsService = metricsService;
this.userRepository = userRepository;
// Use injected services to build UI
Div metricsPanel = new Div();
metricsPanel.setText(metricsService.getCurrentMetrics());
getBoundComponent().add(metricsPanel);
}
}
The constructor can receive:
- Services annotated with
@Service
,@Repository
, or@Component
- Spring Data repositories (
JpaRepository
,CrudRepository
) - Configuration values via
@Value
annotations - Spring infrastructure beans (
ApplicationContext
,Environment
) - Any bean registered in the Spring context
Working example
This example demonstrates a complete dependency injection scenario where a Spring service is injected into a webforJ route. The service manages business logic while the route handles UI presentation.
First, define a standard Spring service using the @Service
annotation. This service will be managed by Spring's container and available for injection:
@Service
public class RandomNumberService {
public Integer getRandomNumber() {
return (int) (Math.random() * 100);
}
}
@Route("/")
public class HelloWorldView extends Composite<FlexLayout> {
private FlexLayout self = getBoundComponent();
private Button btn = new Button("Generate Random Number");
public HelloWorldView(RandomNumberService service) {
self.setDirection(FlexDirection.COLUMN);
self.setMaxWidth(300);
self.setStyle("margin", "1em auto");
btn.setPrefixComponent(TablerIcon.create("dice"))
.setTheme(ButtonTheme.GRAY)
.addClickListener(e -> {
Toast.show("The new random number is " + service.getRandomNumber(), Theme.SUCCESS);
});
self.add(btn);
}
}
In this example, the RandomNumberService
is a standard Spring service bean. The HelloWorldView
route declares it as a constructor parameter, and Spring automatically provides the service instance when webforJ creates the route.
Notice that the route class only uses the @Route
annotation - no Spring stereotypes like @Component
or @Controller
are needed. When a user navigates to the root path /
, webforJ:
- Creates a new instance of
HelloWorldView
- Asks Spring to resolve the
RandomNumberService
dependency - Passes the service to the constructor
- The route uses the injected service to handle button clicks
This pattern works with any Spring bean - services, repositories, configuration classes, or custom components. The dependency injection happens transparently, allowing you to focus on building your UI while Spring manages the wiring.