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
- Instantiation
- Populate Properties
- BeanNameAware
- BeanFactoryAware
- ApplicationContextAware
- Pre-initialization (BeanPostProcessor)
- InitializingBean
- Custom Init Method
- Post-initialization (BeanPostProcessor)
- Bean Ready
- Destruction (DisposableBean)
- 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
- singleton (default)
- prototype
- request
- session
- application
- 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
}
}