Java: técnica Sencilla para la anotación basada en la inyección de código?

Hay una manera para que este código funcione?

LogonControl.java

@Audit(AuditType.LOGON)
public void login(String username, String password) {
 //do login
}

AuditHandler.java

public void audit(AuditType auditType) {
 //persist audit
}

Endgame ser, que cada vez que inicio de sesión() es llamado, de auditoría() es llamado también, con la correspondiente audittype.

Me imagino AOP es, probablemente, la solución a esto, pero me gustaría ser tan simple como sea posible (la AspectJ tutoriales que he mirado normalmente tienen muy complicado de anotaciones).

Nota: yo no quiero tener que fijar de antemano los métodos que se llame de auditoría, estoy escribiendo esto para un marco extensible, y otros puede que necesite utilizar.

¿Qué debe hacer el código? Debe la auditoría() el método se llama cada vez que un método anotado con @Auditoría se llama?
Luontola – sí, exactamente.

OriginalEl autor Robert Wilson | 2009-07-03

3 respuestas

  1. 14

    El uso de la reflexión es fácil anotar un método con @Auditoría, como corredores de la prueba de JUnit:

    public interface Login {
    
        void login(String name, String password);
     }
    
    public class LoginImpl implements Login {
    
        @Audit(handler = LoginHandler.class)
        public void login(String name, String password) {
            System.out.println("login");
        }
    
    }

    @Auditoría se define como:

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface Audit {
    
       Class<? extends Handler> handler();
    }

    donde el Controlador es:

    interface Handler {
    
        void handle();
    }
    
    class LoginHandler implements Handler {
    
        public void handle() {
            System.out.println("HANDLER CALLED!");
        }
    }

    y ahora el código real:

    public class LoginFactory {
    
        private static class AuditInvocationHandler implements InvocationHandler {
    
            private final Login realLogin;
    
            public AuditInvocationHandler(Login realLogin) {
                this.realLogin = realLogin;
            }
    
            public Object invoke(Object proxy, Method method, Object[] args) 
                          throws Throwable {
                Method realMethod = realLogin.getClass().getMethod(
                                            method.getName(), 
                                            method.getParameterTypes());
                Audit audit = realMethod.getAnnotation(Audit.class);
    
                if (audit != null) {
                    audit.handler().newInstance().handle();
                }
    
                return method.invoke(realLogin, args);
            }
        }
    
        public static Login createLogin() {
            return (Login) Proxy.newProxyInstance(
                    LoginFactory.class.getClassLoader(),
                    new Class[]{Login.class},
                    new AuditInvocationHandler(new LoginImpl()));
        }
    }

    @Test:

        Login login = LoginFactory.createLogin();
        login.login("user", "secret");
        login.logout();

    de salida:

    CONTROLADOR DE LLAMADA! 
    inicio de sesión 
    cierre de sesión 
    
    Parece que la mejor solución. Tenía la esperanza de ser capaz de mantener mi código tal y como está y sólo tiene que añadir anotaciones, pero después de un gran trabajo de investigación, yo no creo que eso sea posible. Saludos.

    OriginalEl autor dfa

  2. 5

    Se hace uso La primavera o Guice.

    Rodar su propio sentido si desea saber cómo las ruedas de trabajo, o si usted piensa que usted puede hacer algo que es mucho más ligero. Sólo asegúrese de que ambas son verdaderas antes de que usted emprenda.

    Confía en mí – no tengo ningún deseo de rodar mi propio, pero la Primavera está OTT para mi uso. Voy a mirar en Guice, al principio se ve bien.
    Mi punto sería que usted no tiene que tragar TODA la Primavera para obtener beneficio de ella. Spring AOP es bastante liviano en comparación con AspectJ (menos potente). Esto puede servir a sus necesidades muy bien. Usted no tiene que tratar con todas las de la Primavera, sólo la pequeña parte que pertenece a la AOP. Me he encontrado con que la Primavera funciona bien para estas situaciones. Es posible introducir en un legado de la aplicación de un estrecho propósito, sin exigir una reescritura total. Intente.
    Ya hay un seguimiento integrada aspecto en la Primavera. Usted podría ser capaz de hacer lo que desea con un poco de configuración y no hay nuevo código.
    puede enviar un enlace a la traza aspecto, por favor.
    Eche un vistazo a los Interceptores en la org.springframework.aop.interceptor del paquete: static.springsource.org/spring/docs/3.0.x/javadoc-api. Estoy pensando en la SimpleTraceInterceptor o PerformanceMonitorInterceptor.

    OriginalEl autor duffymo

  3. 1

    Tener una mirada en la intercepción de los métodos en Guice: http://code.google.com/p/google-guice/wiki/AOP

    Un enfoque similar debería funcionar con cualquier AOP marco.

    Gracias por que. Esta línea me asusta un poco: “no es posible utilizar el método de intercepción sobre los casos en que no se construyen por Guice.” Por mi entendimiento, esto significaría que tendría que utilizar Guice.getInstance(LogonController.class) antes de que el método de intercepción va a trabajar? Voy a mirar si esto es posible en otro AOP marco.
    Esto significa que Guice tendrá que construir el objeto, pero esto no significa que usted tendrá que pedir Guice a construir. El objeto puede ser inyectado en otro objeto, que es construida por Guice. Esencialmente, Guice vendría a sustituir a la Fábrica en la solución que dfa dio.

    OriginalEl autor Esko Luontola

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *