Spring Core Concepts

1. Dependency Injection (DI)

1.1 Định nghĩa

  • Là một design pattern cho phép loại bỏ hard-coded dependencies và làm cho ứng dụng dễ test và maintain hơn
  • Spring IoC Container sẽ inject các dependencies vào class khi cần thiết

1.2 Các Loại Dependency Injection

// 1. Constructor Injection (Recommended)
@Service
public class UserService {
    private final UserRepository userRepository;
    private final EmailService emailService;

    @Autowired // Optional từ Spring 4.3
    public UserService(UserRepository userRepository, EmailService emailService) {
        this.userRepository = userRepository;
        this.emailService = emailService;
    }
}

// 2. Setter Injection
@Service
public class UserService {
    private UserRepository userRepository;

    @Autowired
    public void setUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
}

// 3. Field Injection (Not Recommended)
@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;
}

2. Inversion of Control (IoC)

2.1 Định nghĩa

  • Là một nguyên lý trong software engineering trong đó flow của chương trình được đảo ngược
  • Thay vì code của chúng ta kiểm soát flow của ứng dụng, framework sẽ kiểm soát flow

2.2 Spring IoC Container

// Configuration class
@Configuration
public class AppConfig {
    @Bean
    public UserService userService() {
        return new UserService(userRepository(), emailService());
    }

    @Bean
    public UserRepository userRepository() {
        return new JpaUserRepository();
    }

    @Bean
    public EmailService emailService() {
        return new SmtpEmailService();
    }
}

// Usage
public class Application {
    public static void main(String[] args) {
        ApplicationContext context = 
            new AnnotationConfigApplicationContext(AppConfig.class);

        UserService userService = context.getBean(UserService.class);
        userService.doSomething();
    }
}

3. Bean Lifecycle

3.1 Các Giai Đoạn Chính

  1. Instantiation
  2. Populate Properties
  3. BeanNameAware
  4. BeanFactoryAware
  5. ApplicationContextAware
  6. Pre-initialization (BeanPostProcessor)
  7. InitializingBean
  8. Custom Init Method
  9. Post-initialization (BeanPostProcessor)
  10. Bean Ready
  11. Destruction (DisposableBean)
  12. Custom Destroy Method

3.2 Ví dụ

@Component
public class UserService implements InitializingBean, DisposableBean {
    @PostConstruct
    public void init() {
        System.out.println("Post Construct");
    }

    @Override
    public void afterPropertiesSet() {
        System.out.println("After Properties Set");
    }

    @PreDestroy
    public void preDestroy() {
        System.out.println("Pre Destroy");
    }

    @Override
    public void destroy() {
        System.out.println("Bean Destroy");
    }
}

4. Bean Scopes

4.1 Các Loại Scope

  1. singleton (default)
  2. prototype
  3. request
  4. session
  5. application
  6. websocket

4.2 Ví dụ

// Singleton Scope (Default)
@Component
@Scope("singleton")
public class UserService {
    // Only one instance will be created
}

// Prototype Scope
@Component
@Scope("prototype")
public class PrototypeBean {
    // New instance created for each request
}

// Request Scope
@Component
@Scope(value = WebApplicationContext.SCOPE_REQUEST, 
       proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestScopedBean {
    // New instance for each HTTP request
}

// Session Scope
@Component
@Scope(value = WebApplicationContext.SCOPE_SESSION, 
       proxyMode = ScopedProxyMode.TARGET_CLASS)
public class SessionScopedBean {
    // New instance for each HTTP session
}

5. Annotation-based Configuration

5.1 Component Scanning

@Configuration
@ComponentScan(basePackages = "com.example")
public class AppConfig {
    // Configuration
}

5.2 Stereotype Annotations

// Component
@Component
public class GenericComponent {
    // Generic component
}

// Service layer
@Service
public class UserService {
    // Business logic
}

// Repository layer
@Repository
public class UserRepository {
    // Data access logic
}

// Controller layer
@Controller
public class UserController {
    // Web layer
}

// RestController (Combination of @Controller and @ResponseBody)
@RestController
public class UserRestController {
    // RESTful web service
}

5.3 Configuration Properties

@Configuration
@ConfigurationProperties(prefix = "app")
public class AppProperties {
    private String name;
    private String description;
    private Map<String, String> additionalHeaders;

    // Getters and setters
}

// application.properties/yml
app.name=My Application
app.description=Sample Description
app.additional-headers.header1=value1
app.additional-headers.header2=value2

6. AOP (Aspect Oriented Programming)

6.1 Định nghĩa

  • Là một programming paradigm cho phép tách các cross-cutting concerns
  • Giúp tăng modularity bằng cách tách các business logic khỏi các cross-cutting concerns

6.2 Ví dụ

// Logging Aspect
@Aspect
@Component
public class LoggingAspect {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Before("execution(* com.example.service.*.*(..))")
    public void logBefore(JoinPoint joinPoint) {
        logger.info("Before executing {}", joinPoint.getSignature().getName());
    }

    @Around("@annotation(Loggable)")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        Object proceed = joinPoint.proceed();
        long executionTime = System.currentTimeMillis() - start;
        logger.info("{} executed in {}ms", joinPoint.getSignature(), executionTime);
        return proceed;
    }

    @AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))", 
                   throwing = "error")
    public void logAfterThrowing(JoinPoint joinPoint, Throwable error) {
        logger.error("Exception in {}.{}() with cause = {}",
            joinPoint.getSignature().getDeclaringTypeName(),
            joinPoint.getSignature().getName(),
            error.getCause() != null ? error.getCause() : "NULL");
    }
}

// Custom annotation for logging
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Loggable {
}

// Usage
@Service
public class UserService {
    @Loggable
    public User findById(Long id) {
        // Method implementation
    }
}