dire_di 1.0.1
dire_di: ^1.0.1 copied to clipboard
A Spring-like dependency injection framework for Dart with auto-wiring capabilities using mirrors.
import 'package:dire_di/dire_di.dart';
// Model classes
class User {
final int id;
final String name;
final String email;
User({required this.id, required this.name, required this.email});
@override
String toString() => 'User(id: $id, name: $name, email: $email)';
}
// Repository layer
@Repository()
class UserRepository {
final List<User> _users = [
User(id: 1, name: 'John Doe', email: 'john@example.com'),
User(id: 2, name: 'Jane Smith', email: 'jane@example.com'),
User(id: 3, name: 'Bob Johnson', email: 'bob@example.com'),
];
Future<User?> findById(int id) async {
// Simulate database delay
await Future.delayed(Duration(milliseconds: 100));
try {
return _users.firstWhere((user) => user.id == id);
} catch (e) {
return null;
}
}
Future<List<User>> findAll() async {
// Simulate database delay
await Future.delayed(Duration(milliseconds: 150));
return List.from(_users);
}
Future<void> save(User user) async {
await Future.delayed(Duration(milliseconds: 200));
final index = _users.indexWhere((u) => u.id == user.id);
if (index != -1) {
_users[index] = user;
} else {
_users.add(user);
}
}
}
// Service layer
@Service()
class UserService {
@Autowired()
late UserRepository userRepository;
@Autowired()
late EmailService emailService;
Future<User?> getUser(int id) async {
print('UserService: Getting user with id $id');
return await userRepository.findById(id);
}
Future<List<User>> getAllUsers() async {
print('UserService: Getting all users');
return await userRepository.findAll();
}
Future<void> createUser(String name, String email) async {
final newId = DateTime.now().millisecondsSinceEpoch;
final user = User(id: newId, name: name, email: email);
await userRepository.save(user);
await emailService.sendWelcomeEmail(user);
print('UserService: Created user $user');
}
}
// Email service interface
abstract class EmailService {
Future<void> sendWelcomeEmail(User user);
Future<void> sendNotification(User user, String message);
}
// Development email service
@Service()
@Profile('development')
@Qualifier('dev')
class DevEmailService implements EmailService {
@override
Future<void> sendWelcomeEmail(User user) async {
print('DEV EMAIL: Welcome ${user.name}! Your account has been created.');
}
@override
Future<void> sendNotification(User user, String message) async {
print('DEV EMAIL: ${user.name}, you have a notification: $message');
}
}
// Production email service
@Service()
@Profile('production')
@Qualifier('prod')
class ProdEmailService implements EmailService {
@override
Future<void> sendWelcomeEmail(User user) async {
// In production, this would send a real email
await Future.delayed(Duration(milliseconds: 500));
print('PROD EMAIL: Sent welcome email to ${user.email}');
}
@override
Future<void> sendNotification(User user, String message) async {
// In production, this would send a real email
await Future.delayed(Duration(milliseconds: 300));
print('PROD EMAIL: Sent notification to ${user.email}: $message');
}
}
// Default email service when no profile matches
@Service()
@ConditionalOnMissingBean(EmailService)
class DefaultEmailService implements EmailService {
@override
Future<void> sendWelcomeEmail(User user) async {
print('DEFAULT EMAIL: Welcome ${user.name}!');
}
@override
Future<void> sendNotification(User user, String message) async {
print('DEFAULT EMAIL: ${user.name}: $message');
}
}
// Controller layer
@Controller()
class UserController {
@Autowired()
late UserService userService;
Future<void> handleGetUser(int id) async {
try {
final user = await userService.getUser(id);
if (user != null) {
print('Controller: Found user: $user');
} else {
print('Controller: User with id $id not found');
}
} catch (e) {
print('Controller: Error getting user: $e');
}
}
Future<void> handleGetAllUsers() async {
try {
final users = await userService.getAllUsers();
print('Controller: Found ${users.length} users:');
for (final user in users) {
print(' - $user');
}
} catch (e) {
print('Controller: Error getting users: $e');
}
}
Future<void> handleCreateUser(String name, String email) async {
try {
await userService.createUser(name, email);
print('Controller: User created successfully');
} catch (e) {
print('Controller: Error creating user: $e');
}
}
}
// Configuration class example
@Configuration()
class AppConfig {
@Bean()
@Singleton()
Map<String, String> createAppProperties() {
return {
'app.name': 'Dire DI Example',
'app.version': '1.0.0',
'feature.email.enabled': 'true',
};
}
@Bean()
@Qualifier('logger')
Logger createLogger() {
return Logger('DireApp');
}
}
// Simple logger class
class Logger {
final String name;
Logger(this.name);
void info(String message) {
print('[$name] INFO: $message');
}
void error(String message, [Object? error]) {
print('[$name] ERROR: $message ${error ?? ''}');
}
}
// Main application
void main() async {
print('=== Dire DI Example Application ===\n');
try {
// Create container with development profile
final container = DireContainer(
activeProfiles: ['development'],
properties: {
'feature.email.enabled': 'true',
'app.env': 'development',
},
);
// Scan for components
print('Scanning for components...');
await container.scan();
print('Container initialized successfully!\n');
// Get the controller
final controller = container.get<UserController>();
// Test getting a user
print('=== Test: Get User by ID ===');
await controller.handleGetUser(1);
await controller.handleGetUser(999); // Non-existent user
print('');
// Test getting all users
print('=== Test: Get All Users ===');
await controller.handleGetAllUsers();
print('');
// Test creating a user
print('=== Test: Create New User ===');
await controller.handleCreateUser('Alice Wilson', 'alice@example.com');
print('');
// Test getting all users again to see the new user
print('=== Test: Get All Users (After Creation) ===');
await controller.handleGetAllUsers();
print('');
// Test getting beans by qualifier
print('=== Test: Get Logger Bean ===');
final logger = container.getByName('logger') as Logger;
logger.info('Application started successfully');
print('');
// Test getting properties bean
print('=== Test: Get Properties Bean ===');
final properties = container.get<Map<String, String>>();
print('App properties:');
properties.forEach((key, value) => print(' $key: $value'));
print('');
// Test multiple email services
print('=== Test: Multiple Email Services ===');
final emailServices = container.getAll<EmailService>();
print('Found ${emailServices.length} email service(s):');
for (int i = 0; i < emailServices.length; i++) {
final service = emailServices[i];
print(' ${i + 1}. ${service.runtimeType}');
}
} catch (e, stackTrace) {
print('Application failed to start: $e');
print('Stack trace: $stackTrace');
}
}