Direct answer
A well-structured Java project typically includes a clear separation of concerns, with dedicated packages for logging, configuration, and environment management. Logging is often handled using a centralized logger, while configuration is managed through external files or databases to ensure flexibility and maintainability in different environments. This approach promotes code organization and reusability.
Java in the Real World
Moving from theory to practice requires knowing the best practices for structuring professional projects: logging, configuration, environment management.
Related deep dive: 16 - Build Tools: Maven e Gradle.
Related deep dive: 18 - Preparazione Framework Enterprise.
What You'll Learn
- Professional project structure
- Logging with SLF4J and Logback
- Externalized configuration
- Environment management (dev, test, prod)
Project Structure
my-project/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/example/
│ │ │ ├── Application.java
│ │ │ ├── config/
│ │ │ ├── controller/
│ │ │ ├── service/
│ │ │ ├── repository/
│ │ │ ├── model/
│ │ │ └── util/
│ │ └── resources/
│ │ ├── application.properties
│ │ ├── application-dev.properties
│ │ ├── application-prod.properties
│ │ └── logback.xml
│ └── test/
│ ├── java/
│ └── resources/
├── pom.xml (or build.gradle)
└── README.md
Logging
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class UserService {
private static final Logger logger = LoggerFactory.getLogger(UserService.class);
public User findUser(Long id) {
logger.debug("Searching for user with ID: {}", id);
try {
User user = repository.findById(id);
logger.info("User found: {}", user.getName());
return user;
} catch (UserNotFoundException e) {
logger.warn("User not found: {}", id);
throw e;
} catch (Exception e) {
logger.error("Error while searching for user", e);
throw new ServiceException("Internal error", e);
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/app.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/app.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d [%thread] %-5level %logger - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="FILE" />
</root>
<logger name="com.example" level="DEBUG" />
</configuration>
Configuration
# Database
db.url=jdbc:postgresql://localhost:5432/mydb
db.username=user
db.password=password
db.pool.size=10
# API
api.timeout.ms=5000
api.retry.count=3
# Feature flags
feature.newUi.enabled=true
import java.io.*;
import java.util.Properties;
public class ConfigurationManager {
private static final Properties props = new Properties();
static {
String env = System.getProperty("app.env", "dev");
String filename = "application-" + env + ".properties";
try (InputStream is = ConfigurationManager.class
.getClassLoader().getResourceAsStream(filename)) {
if (is != null) {
props.load(is);
}
} catch (IOException e) {
throw new RuntimeException("Unable to load configuration", e);
}
}
public static String get(String key) {
return props.getProperty(key);
}
public static int getInt(String key, int defaultValue) {
String value = props.getProperty(key);
return value != null ? Integer.parseInt(value) : defaultValue;
}
public static boolean getBoolean(String key) {
return Boolean.parseBoolean(props.getProperty(key));
}
}
// Usage
String dbUrl = ConfigurationManager.get("db.url");
int timeout = ConfigurationManager.getInt("api.timeout.ms", 3000);
Best Practices
Rules for Professional Projects
- Separate configuration from code: properties files, environment variables
- Log in a structured way: appropriate levels, no System.out
- Use architectural layers: controller, service, repository
- Automated testing: unit, integration, e2e
- Document: README, Javadoc for public APIs
- Handle exceptions: centralized, with logging
Frequently asked questions
What are some best practices for structuring professional Java projects?
The article mentions logging, configuration, and environment management as key areas to focus on.
How can I manage different environments in my Java project?
Environment management is mentioned as one of the best practices for structuring professional projects.
What are some tools related to build automation that are relevant to Java development?
The article mentions Maven and Gradle as examples of build tools, with a link to a deeper dive on these topics.
How can I handle configuration in my Java project?
Configuration is mentioned as one of the best practices for structuring professional projects.
Commenti
Caricamento commenti...
Sign in to comment