Although they are competitors, their approach and philosophy are radically different.
Spring aims to promote best-of-breed, mix-and-match, use-only-what-you-need kind of development, and portability across all Java EE servlet web servers (most notably Apache Tomcat). That is, because the application server is Spring itself.
Java EE on the other hand, gives you the full package. It has changed a lot now with Java EE 6, in that you don't have to use all of Java EE's components to use Java EE 6. The powerful-ness of Java EE 6 comes from the standard specification of technologies, which is also its weakness: it's not really meant to be flexible.
Now when I'm talking Java EE 6, I meant the components for a web application, which are: Servlet 3.0, EJB 3.1, CDI, JSF 2.0 + Facelets, JPA.
However when I'm talking Spring, I'm mostly talking about Spring Framework, and less of the rest of the Spring Portfolio (e.g. Spring MVC, Spring Web Flow, Spring Security, etc.)
Why I mentioned that, is because there is a noticeable shift from SpringSource, the maker of Spring Framework.
In its Spring Framework version 2.5, Spring is making developers enjoy the most of Java EE 5 with:
* ability to deploy on any servlet container (since Spring "application server" is embedded)
* choice of backend implementations (JPA vs. Hibernate)
* easier to use templates to use an API (e.g. HibernateTemplate)
* enabling dependency injection to any web framework
However, recent APIs and specifications reduce the significance the above benefits of using Spring.
For example, if you're using JPA (Java Persistence API), there's not much gain of using JpaTemplate to standard JPA API. This is compared to the gain of using HibernateTemplate to Hibernate API.
In fact, JpaTemplate will make your application *less* portable. Which is what you want out of Spring. Strange, isn't it?
CDI (Java Context and Dependency Injection aka JSR 299) and Bean Validation (JSR 303) specs make this matter worse for Spring.
CDI is not only a better dependency injection than Spring, but it's a standard (Spring's XML format and annotations are always proprietary). Moreover, Spring doesn't (yet?) support CDI.
Bean Validation makes Spring MVC's validations look ancient. You can use Bean Validation with Spring using Hibernate Validator, but it's not an integral part of Spring.
Perhaps this happens because SpringSource is focusing more on its corporate strategy than the Spring philosophy.
With SpringSource always expanding its portfolio of technologies, they're now a Java application server company and infrastructure provider (with parent company VMware). Surely it's in their best interest to lock-in customers with proprietary technologies than open specifications?
Corporate politics aside, both Spring and Java EE are actually converging when you compare it with a few years ago. You can write code that work in both Spring and Java EE environments. Fortunately, the part that you still need to get specific on is only configuration... i.e. Dependency Injection.
Beyond that though, it's a completely different arena. You can assume Java EE 6 apps use JSF 2.0, but who knows what eccentric web framework is used in a Spring app?
Spring promotes Spring MVC, but it's not the only choice. Even if it's Spring MVC, there are so many ways to configure a Spring MVC app. Even more when you add Spring Web Flow. It's too flexible!
A Java EE 6 application server enables easily deployment of Java EE 6 apps. However, you don't always have to use a Java EE 6 server to use a technology from Java EE 6. For example if you use CDI, you can use an open source implementation like Weld, and run your app in Tomcat.
In the end, who will win: Spring or Java EE? Let me know what you think in the comments.