Java: ¿Cuál es la forma más rápida de inyectar campos usando la reflexión?
-
06-07-2019 - |
Pregunta
Supongamos que tengo muchas clases, que se construyen utilizando la reflexión de Java (por alguna razón). Ahora necesito post-inyectar valores a los campos, que son
anotado con @PostInject
.
public class SomeClass {
@PostInject
private final String someString = null;
public void someMethod() {
// here, someString has a value.
}
}
Mi pregunta es: ¿cuál es una forma rápida de establecer un campo usando la reflexión?
Recuerde, necesito hacer esto muy a menudo en muchas clases, eso es
por qué el rendimiento es relevante.
Lo que haría por intuición se muestra en este pseudocódigo:
- obtener todos los campos de la clase
clazz.getFields();
- check, que están anotados con @PostInject
eachField.getAnnotation(PostInject.class);
- hacer estos campos accesibles
eachAnnotatedField.setAccessible(true);
- establecerlos en un cierto valor
eachAnnotatedField.set (clazz, someValue);
Me temo que obtener todos los campos es lo más lento.
¿Puedo obtener un campo cuando lo conozco desde el principio?
NOTA: No puedo dejar que las clases implementen alguna interfaz, lo que
Permitir establecer los campos utilizando un método. Necesito POJOs.
NOTA2: Por qué quiero la inyección posterior al campo: desde el punto de vista de un usuario de API, debe ser posible utilizar los campos finales. Además, cuando la API no conoce los tipos y la cantidad de campos a priori, es imposible lograr la inicialización de los campos utilizando una interfaz.
NOTA2b: Desde el punto de vista del usuario, el contrato final no está roto. Se queda final. Primero, un campo se inicializa, luego no se puede cambiar. Por cierto: hay muchas API que usan este concepto, una de ellas es JAXB (parte del JDK).
Solución
¿Qué tal hacer los pasos 1 a 3 justo después de construir el objeto y guardar el conjunto de campos anotados que obtiene en el propio objeto o al mantener un mapa separado de clase en un conjunto de campos anotados?
Luego, cuando necesite actualizar los campos inyectados en un objeto, recupere el conjunto del objeto o del mapa separado y realice el paso 4.
Otros consejos
No sé si es bueno, pero este proyecto parece que sería Haz lo que quieras. Cita:
Un conjunto de utilidades de reflexión y Utilidades diversas relacionadas con trabajando con clases y sus campos sin dependencias que es compatible con java 1.5 y genéricos.
Los datos de reflexión de caché de utilidades para operación de alto rendimiento pero utiliza caché débil / suave para evitar manteniendo abiertos los cargadores de clase y provocando los cachés para existir en la memoria permanentemente. La capacidad de anular el mecanismo de almacenamiento en caché con el suyo es compatible.
Otra opción, como usted dice que conoce los pocos campos en cuestión desde el principio, es solicitar solo esos campos o métodos.
Ejemplo: vea getDeclaredMethod
o getDeclaredField
en java / lang / Class.html
Puede explotar los marcos existentes que permiten inyectar dependencias en la construcción de objetos. Por ejemplo, Spring permite hacer eso con aspecto de tejido. La idea general es que defina dependencias de bean en el nivel de primavera y simplemente marque las clases de destino para aconsejar su creación de objetos. La lógica de resolución de dependencia real se inyecta directamente en el código de bytes de la clase (es posible utilizar el tejido de tiempo de compilación o de carga).
La forma más rápida de hacer algo con la reflexión es almacenar en caché las clases reales de API de Reflection siempre que sea posible. Por ejemplo, hace muy poco hice un manipulador POJO más dinámico que creo que es una de esas cosas que todo el mundo termina haciendo en algún momento que me permite hacer esto:
Object o = ...
BeanPropertyController c = BeanPropertyController.of(o);
for (String propertyName : c.getPropertyNames()) {
if (c.access(propertyName) == null &&
c.typeOf(propertyName).equals(String.class)) {
c.mutate(propertyName, "");
}
}
La forma en que funciona es que básicamente tiene ese único objeto controlador que carga de manera diferida todas las propiedades del bean ( nota: algo de magia involucrada ) y luego las reutiliza siempre que el objeto controlador real sea viva. Todo lo que puedo decir es que simplemente guardando los objetos del Método en sí, logré convertirlo en algo malditamente rápido y estoy muy orgulloso de eso e incluso considerando liberarlo asumiendo que puedo resolver los derechos de autor, etc.