Retire Java intento repetido, captura, por último repetitivo de DAO
-
10-10-2019 - |
Pregunta
Tengo una clase DAO con muchos métodos que tienen una gran cantidad de código repetido a lo largo de las líneas de: -
public void method1(...) {
Connection conn = null;
try {
//custom code here
} catch (SQLException e) {
LOG.error("Error accessing the database.", e);
throw new DatabaseException();
} catch (QueryNotFoundException e) {
LOG.error("Error accessing the database.", e);
throw new DatabaseException();
} finally {
if (conn != null)
connectionPool.returnConnection(conn);
}
public void method2(...) {
Connection conn = null;
try {
//different custom code here
} catch (SQLException e) {
LOG.error("Error accessing the database.", e);
throw new DatabaseException();
} catch (QueryNotFoundException e) {
LOG.error("Error accessing the database.", e);
throw new DatabaseException();
} finally {
if (conn != null)
connectionPool.returnConnection(conn);
}
Me gustaría reestructurar esta clase para poner el try, catch, finalmente, en un lugar a repetation evitar. ¿Cómo voy a lograr esto?
Solución
Crea una interfaz para ex. Ejecutable:
public interface Executable() {
void exec() throws SqlException();
}
Refactor cada uno de su método DAO a:
public void method1() {
execute(new Executable() {
@Override
public void exec() throws SqlException() {
// your code here
}
});
}
Crea el siguiente método de ejecución en su DAO:
private void execute(Executor ex) {
try {
ex.exec();
} catch(...) {
...
} finally {
...
}
}
Otros consejos
Creo que lo que se debe utilizar es Spring-JDBC 's JdbcTemplate
Incluso si usted no utiliza la primavera de gestionar su solicitud, se podría utilizar mediante programación JdbcTemplate abstraer toda la gestión de la conexión y control de errores.
Ejemplo código:
List<Actor> actors = this.jdbcTemplate.query(
"select first_name, last_name from t_actor",
new RowMapper<Actor>() {
public Actor mapRow(ResultSet rs, int rowNum)
throws SQLException {
Actor actor = new Actor();
actor.setFirstName(rs.getString("first_name"));
actor.setLastName(rs.getString("last_name"));
return actor;
}
});
Como se puede ver, que hacer frente a la consulta real solamente, no con la materia de infraestructura alrededor de ella.
Yo usaría AOP para un patrón de registro commong aquí. Por ejemplo: -
<bean id="exceptionLogger" class="my.good.ExceptionLogger" />
<aop:config>
<aop:pointcut id="allDaoMethods" expression="execution(* my.dao.*(..))" />
<aop:aspect id="daoLogger" ref="exceptionLogger">
<aop:after-throwing pointcut-ref="allDaoMethods"
method="logIt"
throwing="e"/>
</aop:aspect>
</aop:config>
Y la clase ExceptionLogger podría ser algo como a continuación: -
public class ExceptionLogger {
private static Logger logger = Logger.getLogger(ExceptionLogger.class);
public void logIt(JoinPoint jp, Exception e) {
StringBuilder msg = new StringBuilder();
msg.append("<whatever makes sense>");
logger.error(msg.toString());
}
}
Esto es similar a la solución de Vladimir sin clases anónimas con posibilidad de valor de retorno de tales métodos.
interface DaoOperation {
void execute() throws SQLException;
}
class Operation1 implements DaoOperation {
public void execute() {
// former method1
}
}
// in case you'd ever like to return value
interface TypedDaoOperation<T> {
T execute() throws SQLException;
}
class Operation2 implements TypedDaoOperation<String> {
public String execute() {
return "something";
}
}
class DaoOperationExecutor {
public void execute(DaoOperation o) {
try {
o.execute();
} catch (SQLException e) {
// handle it as you want
}
}
public <T>T execute(TypedDaoOperation<T> o) {
try {
return o.execute();
} catch (SQLException e) {
// handle it as you want
}
}
}