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:
| Spring | Sproogy | Purpose |
|---|---|---|
@SpringBootApplication | @SproogyApplication | Main application class |
@Component | @Component | Generic managed bean |
@Service | @Service | Business logic layer |
@Controller | @Controller | Request handlers |
@Repository | @Repository | Data access layer |
@Configuration | @Configuration | Bean definition class |
@Bean | @Bean | Factory method for beans |
@Autowired | @Autowired | Dependency injection |
@Value | @Value | Inject configuration values |
@Qualifier | @Qualifier | Specify bean by name |
@Primary | @Primary | Default 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:
| Spring | Sproogy | When It Runs |
|---|---|---|
@PostConstruct | Not available (use constructor) | After DI |
CommandLineRunner | SproogyBootStrap (ServiceLoader) | After context initialized |
ApplicationListener | Not available | On 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:
- Uses WebSockets or custom TCP protocols
- Needs ultra-low latency (no HTTP overhead)
- Requires persistent connections
- Communicates with non-HTTP systems
What Transfers Directly
✅ Your JPA entities - No changes needed
✅ Your repository interfaces - Same syntax
✅ Your service layer - Just swap @Service
✅ Your 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
-
Keep your domain layer intact:
// No changes needed
@Entity
public class User { /* ... */ }
@Service
public class UserService { /* ... */ }
@Repository
public interface UserRepository extends JpaRepository<User, Long> { /* ... */ } -
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));
}
} -
Implement SSL configuration:
@Component
public class SSLConfig implements SSLFactoryLoader {
@Override
public SSLServerSocketFactory getSSLServerSocketFactory() throws Exception {
// Implement SSL setup (was auto-configured in Spring)
}
} -
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 -
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 Concept | Sproogy Equivalent | Notes |
|---|---|---|
ApplicationContext | ApplicationContext | Same interface |
BeanFactory | BeanFactory | Same concept, different implementation |
@RequestMapping | @AppMapping | Maps to socket endpoint instead of HTTP path |
@PathVariable | @PathVariable | Identical usage |
@RequestParam | @RequestParam | Identical usage |
RestTemplate | SocketTemplate | Client-side communication |
@ExceptionHandler | Not available | Handle exceptions in filters or controllers |
@ControllerAdvice | Not available | Use filters for global logic |
HttpServletRequest | Request | Custom request object |
HttpServletResponse | Response | Custom 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
- ✅ Start with Getting Started - setup is similar
- ✅ Read Dependency Injection - concepts are identical
- ✅ Study Socket Programming - this is new
- ✅ Explore Filters - similar to Servlet filters
- ✅ Review JPA - same as Spring Data JPA
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: