Application Servers

My last post talked about something I called megaservices. The idea isn’t new. Before microservices, serverless, and a shelf full of point tools, enterprise teams built on application servers. During my PhD I closely collaborated with JBoss on their application server and became intimately familiar with the inner workings of an application server.

What is an application server?

Think of a platform that looks a little like an always‑on PaaS living in your data center. Instead of starting a self‑contained app that happens to include a web server, you deploy your app into a host that’s already running. The host manages process lifecycle, provides shared services, and exposes a consistent way to configure and observe everything on it. Communication, persistence, transactions, messaging, security, monitoring, clustering—the platform handled the scaffolding so the application could focus on its job. Classic names include JBoss/WildFly, WebLogic, WebSphere, and GlassFish.

How the programming model felt

You wrote plain business logic and the server took responsibility for the hard operational concerns: when to create and reuse objects, how many could run in parallel, and how to clean them up safely. Concurrency rules, resource pooling, and error handling lived in the platform.

You built a single archive, copied it to the server’s deployment area, and the platform took it from there—validating, wiring resources, and starting it. Teams used that same mechanism for hot‑reload in development and controlled, versioned rollouts in production through the admin console or scripts.

Many applications coexisted on one server without chaos. Each deployment ran in its own isolated space, which prevented library collisions. Shared infrastructure—like a database connection or a message destination—was opt‑in and explicit. Otherwise, applications lived independent lives while still benefiting from the same operational guardrails. Perhaps, application servers were the true embodiment of the serverless concept.

Communication

Services could call each other like local code while the platform handled the remoting—no URLs to build, no headers to juggle, no bodies to parse. The platform was even smart enough to keep track of transactional and security context through invocations.

Publishing and consuming messages was also part of the server’s job. You wired an application endpoint to a queue or topic and let the platform handle concurrency, retries, redelivery, and durability. Event‑driven features were native—no sidecars, no extra daemon to babysit.

Data access without ceremony

Instead of sprinkling connection strings and pool settings through your code, object‑relational mapping was part of the platform too: application code worked with domain objects while the runtime handled SQL, batching, and caching. Database configuration was part of the platform, not the application.

Integration of communication, component lifecycles and persistence, allowed for transactions to be managed by the platform. When multiple operations needed to succeed or fail together, you declared them as being part of the same transaction and the platform coordinated it across participating resources. You didn’t hand‑code commit/rollback choreography in every endpoint. The result was predictable behavior under failure and fewer bespoke patterns to maintain.

Cross cutting concerns

Authentication and authorization lived at the platform boundary. Identity sources and role mappings were defined once and applied them uniformly to every application on the host. The appeal wasn’t novelty; it was consistency.

Operations sat close to the runtime. Admin consoles exposed status, thread pools, caches, deployments, and alerts.

Session replication, health checks, and failover were built‑in. Scaling out meant adding nodes to a cluster the platform already understood. My research focused on how to replicate state consistently with the distributed transactions. The big idea is that resilience wasn’t a bespoke project per team; it was a dial you turned on the platform.

What happened to application servers?

Over time the model lost ground for practical reasons: slow‑moving standards, a significant learning curve, overkill for simple apps yet too prescriptive for niche ones, other frameworks with cleaner syntax and faster iteration, and the shift to heterogeneous tech stacks.

The once‑bundled features of the application server now live in separate products and cloud services—message brokers, identity providers, observability stacks, container orchestrators, and more. We gained flexibility, but also many more moving parts. A typical organization’s platform is now far more complex, assembled by an entire team using disparate OTS products and services. PaaS offerings exist, but their scope and defaults rarely match the cohesion of classic application servers or the amount of “out‑of‑the‑box” capability you got from a single runtime.

Application servers were opinionated runtimes that made cross‑cutting concerns someone else’s problem. If you grew up in microservices, it’s worth knowing what we used to get on day one so you can decide what to rebuild, what to centralize, and what to simply stop doing.

© 2025 Jaksa Vuckovic. Built with SvelteKit