Service class
Service annotation for service layer components
This annotation marks a class as a service component. It's a specialization of @Component for the service layer.
Example Usage:
@Service()
class UserService {
final UserRepository userRepository;
final EmailService emailService;
UserService(this.userRepository, this.emailService);
Future<List<User>> findAll() async {
return userRepository.findAll();
}
Future<User> findById(String id) async {
final user = await userRepository.findById(id);
if (user == null) {
throw NotFoundException('User not found: $id');
}
return user;
}
@Transactional()
Future<User> create(CreateUserRequest request) async {
final user = User(
id: generateId(),
name: request.name,
email: request.email,
createdAt: DateTime.now(),
);
final savedUser = await userRepository.save(user);
await emailService.sendWelcomeEmail(savedUser.email);
return savedUser;
}
@Transactional()
Future<User> update(String id, UpdateUserRequest request) async {
final existingUser = await findById(id);
final updatedUser = existingUser.copyWith(
name: request.name,
email: request.email,
updatedAt: DateTime.now(),
);
return userRepository.save(updatedUser);
}
@Transactional()
Future<void> delete(String id) async {
final user = await findById(id);
await userRepository.delete(user.id);
await emailService.sendGoodbyeEmail(user.email);
}
}
Marks a class as a Service Component within the dependency injection (DI) container.
The @Service
annotation designates a class as a singleton, typically containing
business logic, application use cases, or domain services. These classes
are automatically detected, instantiated once, and injected wherever required.
It is semantically equivalent to @Component
, but helps communicate the role
of the class more explicitly (in the spirit of Domain-Driven Design).
π§© Purpose:
- Declare stateless, reusable business logic components
- Promote separation of concerns between services, repositories, and controllers
- Automatically register the service in the DI container
π§ͺ Example:
@Service()
class UserService {
final UserRepository _repo;
UserService(this._repo);
User? findById(String id) => _repo.findById(id);
}
The above service can now be injected:
class UserController {
final UserService _userService;
UserController(this._userService);
}
π¦ Typical Use Cases:
Type | Role |
---|---|
UserService |
Business logic for user management |
PaymentProcessorService |
Coordinates payment workflows |
AuthService |
Authentication/authorization utilities |
π§ Characteristics:
- Singleton Scope: A single instance is shared across the application.
- Dependency-Aware: Can depend on other components like repositories, configurations, etc.
- No side effects in constructor: Avoid non-trivial logic in the constructor.
π§ Usage Notes:
- You can inject this class into other services, controllers, or components.
- Use
@Service()
when your class contains core business logic and requires clear separation from lower-level infrastructure (like@Repository()
).
π― Target:
This annotation can only be applied to class declarations:
@Service()
class EmailSender {
void send(String email) => print('Sending to $email');
}
π§© Related Annotations:
@Component
β Generic DI component base@Repository
β Specializes in persistence/data access@Configuration
β Declares pod-producing configuration classes@Controller
β (Optional) Marks HTTP/web-facing logic
β Best Practices:
- Keep
@Service
classes stateless or minimally stateful - Inject required dependencies through constructor
- Avoid tight coupling with frameworks for better testability
π‘ Tip:
If you're building your own DI container, treat @Service()
as a specialization of @Component()
with singleton semantics.
- Annotations
-
- @Component()
- @Target.new({TargetKind.classType})
Properties
- annotationType β Type
-
Returns the annotation _type of this annotation.
no setter
- hashCode β int
-
The hash code for this object.
no setterinherited
- runtimeType β Type
-
A representation of the runtime type of the object.
no setterinherited
- value β String?
-
Optional service name
final
Methods
-
equalizedProperties(
) β List< Object?> -
Mixin-style contract for value-based equality,
hashCode
, andtoString
. -
equals(
Object other) β bool -
Checks whether the given object is logically equivalent to this annotation.
inherited
-
noSuchMethod(
Invocation invocation) β dynamic -
Invoked when a nonexistent method or property is accessed.
inherited
-
toString(
) β String - Returns a string representation of this annotation.
Operators
-
operator ==(
Object other) β bool -
The equality operator.
inherited