2009-02-23 26 views
16

Quiero interceptar todas las invocaciones de métodos a alguna clase MyClass para poder reaccionar en algunas invocaciones de setter.¿Cómo se intercepta una invocación a un método con funciones Java estándar (sin AspectJ, etc.)?

Traté de usar proxies dinámicos, pero por lo que yo sé, esto sólo funciona para las clases que implementan alguna de las interfaces. Pero MyClass no tiene esa interfaz.

¿Hay alguna otra forma, además de la implementación de una clase contenedora, que los delegados todas las invocaciones a un miembro, que es una instancia de la MiClase o Besided usando AOP?

Respuesta

23

Como nota, no se puede usar proxies dinámicos JDK (sin interfaz), pero utilizando Spring y CGLIB (JAR incluido con la primavera), puede hacer lo siguiente:

public class Foo 
{ 
    public void setBar() 
    { 
     throw new UnsupportedOperationException("should not go here"); 
    } 

    public void redirected() 
    { 
     System.out.println("Yiha"); 
    } 
} 

Foo foo = new Foo(); 
ProxyFactory pf = new ProxyFactory(foo); 

pf.addAdvice(new MethodInterceptor() 
{ 
    public Object invoke(MethodInvocation mi) throws Throwable 
    { 
     if (mi.getMethod().getName().startsWith("set")) 
     { 
      Method redirect = mi.getThis().getClass().getMethod("redirected"); 
      redirect.invoke(mi.getThis()); 
     } 
     return null; 
    } 
}); 

Foo proxy = (Foo) pf.getProxy(); 
proxy.setBar(); // prints "Yiha" 
+0

¡Gracias! Me salvó el día. –

+0

Al interceptar un método, ¿es posible leer los argumentos que se le pasan? – aryaxt

+0

sí que es posible ... para (arg Objeto: mi.getArguments()) { \t \t \t \t sysout (arg.getClass() + "-" + arg); \t \t \t} – Skabdus

13

Si usted está preparado para hacer algo realmente feo, echar un vistazo a:

http://docs.oracle.com/javase/7/docs/technotes/guides/jpda/

Básicamente, la interfaz de depuración debe permitirá conectar como un depurador, y por lo tanto interceptar llamadas. Tenga en cuenta que creo que esta es una mala idea realmente, pero me preguntó si era posible.

+8

+1 para el valor de hack –

+0

De acuerdo. Bastante feo. – Jus12

0

No hay mucha magia en AspectJ. Puedes escribir tu propio agente. http://java.sun.com/javase/6/docs/api/java/lang/instrument/package-summary.html parece ser un buen punto de partida.

+1

Creo que subestimas el trabajo necesario para los agentes de calidad de producción. –

+0

Lo siento, no quise quitar ningún crédito de AspectJ. Es algo maravilloso y lo estoy usando con mucho éxito. Solo quise decir que un agente simple para interceptar métodos no es muy difícil de escribir. Gracias por corregirme. –

2

Java no tiene ningún características del lenguaje reales para la interceptación de método (no estoy seguro cualquier idioma estática hace)

Yo un poco como la idea de Nick de la utilización de la interfaz de depuración, eso es sólo decir.

creo que la respuesta corta es que necesita: No, no hay una manera de interceptar una llamada a un método en Java sin tener que reemplazar la clase utilizando un proxy o envoltorio.

Nota: Las bibliotecas de AOP solo hacen que esto suceda automáticamente.

1

Algunos de los gurús de Java puede fruncir el ceño a esto, pero he tenido algunos buenos resultados con evitar los tipos primitivos y definidores del todo. Mi clase se ve así:

class Employee extends SmartPojo { 
    public SmartString name; 
    public SmartInt age; 
} 

Notarás dos cosas: 1. todo es público. 2. Sin constructor.

La magia sucede en SmartPojo la que busca para cualquier campo que implementa la interfaz "inteligente" y lo inicializa. Como esto no es primitivo (y no hay una clase final), puedo agregar los métodos set() y get() para todos los campos en cualquier lugar de mi modelo en un solo lugar. Así que ya no se pierden setter/getter, es increíblemente simple agregar notificaciones (también en un solo lugar), etc.

Cierto, esto ya no es POJO y no es un Bean en la mayoría de los sentidos, pero he encontrado que las viejas ideas me limitan más de lo que ayudan. YMMV.

+0

esto es básicamente lo que hace Grails con sus objetos de dominio. Sin embargo, debido a que pueden implementarlo con groovy, es mucho más agradable, y no necesitarán tener cada propiedad implementando una interfaz "inteligente". – Chii

+0

Necesitaba una solución solo de Java. Lo intenté con Groovy también y, aunque el código es mucho más compacto, no es tan agradable. Soy un gran admirador de Groovy, pero creo que 1.x sigue siendo un poco ... "incompleto". –

+0

¿Puedes compartir el código de 'SmartPojo'? –

0
  1. ¿Por qué su clase no puede implementar una interfaz? Podrías extraer alguna interfaz que contenga todos los métodos que quieras interceptar y usar fácilmente el mecanismo de proxies dinámicos. También es una buena práctica de programación codificar con interfaces y no con clases.

  2. Se puede usar marco de primavera con capacidades primavera AOP (que están utilizando proxies dinámicos dentro) para hacerlo.Simplemente tendrá que definir su clase como Spring Bean en el archivo de configuración y los clientes de su clase tendrán que obtener su instancia del contexto de la aplicación Spring o como una dependencia automáticamente (definiendo el método setMyClass (MyClass mc) por ejemplo) Desde allí, puede ir fácilmente a la definición de un aspecto que intercepta todas las llamadas a métodos de esta clase.

+0

¿Quizás esté intentando depurar una clase que no escribió contenida en una biblioteca de terceros? –

0

Para la interceptación de la invocación del método java, una AspectJ es una buena herramienta para usar. A través de la cual se pueden interceptar llamadas, ejecuciones, etc. de manera eficiente. Estoy usando la misma herramienta para interceptar llamadas a métodos java. Podemos aplicar puntos de control y aspectos para interceptar cualquier llamada al método java. para mera información, lea this

Cuestiones relacionadas