Skip to main content

Spring Framework Comparison

If you're coming from Spring, this guide will help you map your existing knowledge to Sproogy concepts.

Similarities: What Feels Familiar

1. Annotation-Based Configuration

Both frameworks use annotations to declare components:

SpringSproogyPurpose
@SpringBootApplication@SproogyApplicationMain application class
@Component@ComponentGeneric managed bean
@Service@ServiceBusiness logic layer
@Controller@ControllerRequest handlers
@Repository@RepositoryData access layer
@Configuration@ConfigurationBean definition class
@Bean@BeanFactory method for beans
@Autowired@AutowiredDependency injection
@Value@ValueInject configuration values
@Qualifier@QualifierSpecify bean by name
@Primary@PrimaryDefault bean when multiple exist

2. Dependency Injection

Both use constructor and field injection:

// Spring & Sproogy: Identical syntax
@Service
public class UserService {

private final UserRepository userRepository;
private final EmailService emailService;

@Autowired
public UserService(UserRepository userRepository, EmailService emailService) {
this.userRepository = userRepository;
this.emailService = emailService;
}
}

3. Configuration Files

Both support externalized configuration:

Spring (application.properties / application.yml):

server:
port: 8080

spring:
datasource:
url: jdbc:mysql://localhost/db
username: ${DB_USER}
password: ${DB_PASSWORD}

Sproogy (application.yml + .env):

# application.yml
application:
socket:
format:
idKey: "id"
payloadKey: "data"

data:
hibernate:
show_sql: "true"
# .env
SOCKET_PORT=8443
DB_USER=admin
DB_PASSWORD=secret

4. JPA Integration

Repository pattern is nearly identical:

// Spring Data JPA & Sproogy: Same interface
@Repository
public interface UserRepository extends JpaRepository<User, Long> {

Optional<User> findByEmail(String email);

@Query("SELECT u FROM User u WHERE u.age > :age")
List<User> findUsersOlderThan(@Param("age") int age);

@Transactional
void deleteByStatus(String status);
}

5. Lifecycle Hooks

Both provide hooks for initialization:

SpringSproogyWhen It Runs
@PostConstructNot available (use constructor)After DI
CommandLineRunnerSproogyBootStrap (ServiceLoader)After context initialized
ApplicationListenerNot availableOn specific events

Differences: What's Unique to Sproogy

1. Transport Layer

Spring Boot:

  • Built for HTTP/HTTPS (Tomcat, Jetty, Undertow)
  • Servlet-based architecture
  • Request/Response via HTTP protocol

Sproogy:

  • Built for TCP/SSL sockets
  • Custom protocol support
  • Request/Response via JSON over sockets
// Spring: HTTP Controller
@RestController
@RequestMapping("/api")
public class UserController {

@GetMapping("/users/{id}")
public ResponseEntity<User> getUser(@PathVariable Long id) {
return ResponseEntity.ok(userService.findById(id));
}
}

// Sproogy: Socket Controller
@Controller
public class UserController {

@AppMapping("/users/{id}")
public ResponseEntity<User> getUser(@PathVariable("id") Long id) {
return ResponseEntity.ok(userService.findById(id));
}
}

2. Request Processing

Spring MVC: Filter Chain → Servlet → Interceptors → Controller

Sproogy: InputTransformer → Deserializer → FilterChain → Controller → Serializer → OutputTransformer

3. Request Format

Spring: HTTP request with headers, body, query params

GET /api/users/123?include=posts HTTP/1.1
Host: example.com
Authorization: Bearer eyJhbGc...
Content-Type: application/json

Sproogy: JSON request with custom keys

{
"id": "req-001",
"endpoint": "/users/123",
"headers": {
"Authorization": "Bearer eyJhbGc..."
},
"data": {
"include": "posts"
}
}

4. Filter Pattern

Spring: Filters are interfaces with doFilter(request, response, chain)

// Spring Filter
@Component
public class LoggingFilter implements Filter {

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {

System.out.println("Before request");
chain.doFilter(request, response); // Continue chain
System.out.println("After request");
}
}

Sproogy: Same concept, different types

// Sproogy Filter
@Component
public class LoggingFilter implements com.sproogy.socket.server.security.filter.Filter {

@Override
public void doFilter(Request request, Response response, FilterChain chain) throws Exception {
System.out.println("Before request");
chain.doFilter(request, response); // Continue chain
System.out.println("After request");
}
}

5. Application Startup

Spring Boot:

@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

Sproogy:

@SproogyApplication(basePackage = "com.example")
public class Application {
public static void main(String[] args) {
SproogyApp.run(Application.class, args);
}
}

6. No Auto-Configuration

Spring Boot: Massive auto-configuration (100+ auto-config classes)

  • Automatically configures Tomcat, Jackson, JPA, Security, etc.
  • Opinionated defaults based on classpath

Sproogy: Minimal auto-configuration

  • You must provide SSL factory implementation
  • Explicit configuration required
// Sproogy: You MUST implement this
@Component
public class SSLConfig implements SSLFactoryLoader {

@Override
public SSLServerSocketFactory getSSLServerSocketFactory() throws Exception {
// Your custom SSL configuration
KeyStore keyStore = KeyStore.getInstance("JKS");
// ... configure manually
return sslContext.getServerSocketFactory();
}
}

7. Scope and Size

Spring Framework:

  • Massive ecosystem: Spring Boot, Spring Security, Spring Cloud, Spring Batch, etc.
  • Hundreds of modules
  • Thousands of classes

Sproogy:

  • Focused scope: IoC/DI + Sockets + JPA
  • 3 modules: core, socket, jpa
  • Lightweight footprint

Migration Guide: Spring → Sproogy

When to Migrate

Consider Sproogy if you're building a Spring application that:

  1. Uses WebSockets or custom TCP protocols
  2. Needs ultra-low latency (no HTTP overhead)
  3. Requires persistent connections
  4. Communicates with non-HTTP systems

What Transfers Directly

Your JPA entities - No changes needed ✅ Your repository interfaces - Same syntax ✅ Your service layer - Just swap @ServiceYour domain models - Pure POJOs work identically ✅ Your test strategies - Mockito/JUnit work the same

What Needs Rewriting

🔄 Controllers - Change from @RestController to @Controller, use @AppMapping instead of @GetMapping 🔄 Security - No Spring Security, implement custom filters 🔄 Configuration - Split between application.yml and .env 🔄 Client code - Use SocketTemplate instead of RestTemplate

Step-by-Step Migration

  1. Keep your domain layer intact:

    // No changes needed
    @Entity
    public class User { /* ... */ }

    @Service
    public class UserService { /* ... */ }

    @Repository
    public interface UserRepository extends JpaRepository<User, Long> { /* ... */ }
  2. Rewrite controllers:

    // Before (Spring)
    @RestController
    @RequestMapping("/api/users")
    public class UserController {

    @GetMapping("/{id}")
    public ResponseEntity<User> getUser(@PathVariable Long id) {
    return ResponseEntity.ok(userService.findById(id));
    }
    }

    // After (Sproogy)
    @Controller
    public class UserController {

    @AppMapping("/users/{id}")
    public ResponseEntity<User> getUser(@PathVariable("id") Long id) {
    return ResponseEntity.ok(userService.findById(id));
    }
    }
  3. Implement SSL configuration:

    @Component
    public class SSLConfig implements SSLFactoryLoader {
    @Override
    public SSLServerSocketFactory getSSLServerSocketFactory() throws Exception {
    // Implement SSL setup (was auto-configured in Spring)
    }
    }
  4. Update configuration:

    # Spring application.yml
    server:
    port: 8080
    spring:
    datasource:
    url: ${DB_URL}

    # Sproogy application.yml + .env
    # application.yml
    application:
    socket:
    format:
    idKey: "id"

    # .env
    SOCKET_PORT=8443
    DB_URL=jdbc:mysql://localhost/db
  5. Replace security filters:

    // Spring Security
    @Configuration
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter { /* ... */ }

    // Sproogy Filter
    @Component
    public class AuthFilter implements Filter {
    @Override
    public void doFilter(Request request, Response response, FilterChain chain) {
    // Custom auth logic
    }
    }

Conceptual Mapping

Spring ConceptSproogy EquivalentNotes
ApplicationContextApplicationContextSame interface
BeanFactoryBeanFactorySame concept, different implementation
@RequestMapping@AppMappingMaps to socket endpoint instead of HTTP path
@PathVariable@PathVariableIdentical usage
@RequestParam@RequestParamIdentical usage
RestTemplateSocketTemplateClient-side communication
@ExceptionHandlerNot availableHandle exceptions in filters or controllers
@ControllerAdviceNot availableUse filters for global logic
HttpServletRequestRequestCustom request object
HttpServletResponseResponseCustom response object
ResponseEntity<T>ResponseEntity<T>Same class

Code Side-by-Side

Spring Boot Application

@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

@RestController
@RequestMapping("/api")
public class UserController {

@Autowired
private UserService userService;

@GetMapping("/users/{id}")
public ResponseEntity<User> getUser(@PathVariable Long id) {
return ResponseEntity.ok(userService.findById(id));
}
}

@Service
public class UserService {

@Autowired
private UserRepository userRepository;

public User findById(Long id) {
return userRepository.findById(id).orElse(null);
}
}

@Repository
public interface UserRepository extends JpaRepository<User, Long> {}

Sproogy Application

@SproogyApplication(basePackage = "com.example")
public class Application {
public static void main(String[] args) {
SproogyApp.run(Application.class, args);
}
}

@Controller
public class UserController {

@Autowired
private UserService userService;

@AppMapping("/users/{id}")
public ResponseEntity<User> getUser(@PathVariable("id") Long id) {
return ResponseEntity.ok(userService.findById(id));
}
}

@Service
public class UserService {

@Autowired
private UserRepository userRepository;

public User findById(Long id) {
return userRepository.findById(id).orElse(null);
}
}

@Repository
public interface UserRepository extends JpaRepository<User, Long> {}

Learning Path for Spring Developers

  1. ✅ Start with Getting Started - setup is similar
  2. ✅ Read Dependency Injection - concepts are identical
  3. ✅ Study Socket Programming - this is new
  4. ✅ Explore Filters - similar to Servlet filters
  5. ✅ Review JPA - same as Spring Data JPA
tip

The hardest part of learning Sproogy as a Spring developer is unlearning HTTP. Focus on understanding how socket communication replaces HTTP requests.

Next Steps

Now that you understand the parallels with Spring, dive deeper into how Sproogy's dependency injection works:

👉 Dependency Injection