Everything is effectively based on Servlets. You can do everything by writing code that extends the HttpServlet class.
The first Java applications on the web (circa 2000) did just that: they subclassed HttpServlet and created all response content with println statements. This was awesome and worked except that the code was too complicated. But it was a heroic era. The Servlet did everything:
It was a dark era because around that time some wicked people starting thinking about the abomination that became known as "Enterprise Java Beans".
This pattern made more sense, you got your vanilla HttpServlet back which you kept for all of the control and you had JSP for the view and beans (ordinary Java Beans even though some perverts used EJBs) for the model. So this resulted in a very clear and nice separation of the MVC concerns.
This pattern is depicted here.
There was nothing really wrong with JSP model 2 except people began arguing whether you should have a single controller servlet (a.k.a. the Front Controller) or whether each JSP page should have its own or any other approach in between. Around that time Struts appeared. Struts was a request-based framework (as they became known) that presented a single "front controller" HttpServlet that then dispathed to various "action" classes which the programmer provided. Spring MVC which is another request-based framework also implements the front controller pattern.
Sadly, also around the same time some unshaven people working in a rat-infested basement came up with idea of JSF and the so-called "component" frameworks.
The basic dichotomy is that between component-oriented frameworks and request-based (a.k.a. action based) frameworks. In a nutshell, component-based frameworks are high-level and evil and suck whereas request-based frameworks are lower-level, expose the HTTP requests and responses, allow you to retain full and fine-level control and smell nice. A more extended description is found here and here (the latter one discussing the new MVC coming with Java EE 8).
The following figure is also instructional:
Request-based frameworks generally make it clear through their APIs that they're working with parsing an HTML request / generating an HTML response, while Component-based frameworks attempt to abstract this away and treat the application as collections of components with renderers and actions to do things.
Request based framework is a web framework that gets user's request then determine what the system should do and give back the response back to the user. So the flow is pretty much linear. You're thinking in actions: what does user want (request) -> what user will get back (response). An example of Request based framework is Struts. The modern Grails is pretty much a Request based framework too.
Component based framework is not like that. There is actually no clear sense of the flow from front to back. An example of it is not JSF, because in some way JSF is pretty much quite the same with Struts (since the creator of Struts and JSF is the same). A good example of Component based framework Tapestry and Wicket. The paradigm in these two framework is different. You don't think in actions or request-response, but components and components. You define a component in your application, and you tell what the component does. But the flow does not have to be linear as in Request based framework.
JSP is a Java view technology running on the server machine which allows you to write template text in client side languages (like HTML, CSS, JavaScript, ect.). JSP supports taglibs, which are backed by pieces of Java code that let you control the page flow or output dynamically. A well-known taglib is JSTL. JSP also supports Expression Language, which can be used to access backend data (via attributes available in the page, request, session and application scopes), mostly in combination with taglibs.
When a JSP is requested for the first time or when the web app starts up, the servlet container will compile it into a class extending HttpServlet and use it during the web app's lifetime. You can find the generated source code in the server's work directory. In for example Tomcat, it's the /work directory. On a JSP request, the servlet container will execute the compiled JSP class and send the generated output (usually just HTML/CSS/JS) through the web server over a network to the client side, which in turn displays it in the web browser.