java - ¿Por qué Spring no es compatible con la inyección directa de dependencias en el campo(excepto en el caso de autowired)?
dependency-injection (3)
Estoy interesado en la inyección directa de dependencias de campo. Tradicionalmente, Spring admite tanto la inyección del constructor (que proporciona argumentos a los constructores) como la inyección basada en el establecimiento (llamada a los usuarios en una llamada).
Sin embargo, Spring también es capaz de la inyección directa de campos (configurando campos miembros de un objeto sin un método de establecimiento), como se evidencia al anotar campos con @Autowired
. El cableado automático se limita a solo "beans", por lo que no se pueden inyectar valores primitivos (aunque esto se puede eludir un poco al crear beans de la clase "java.lang.String"; esto funciona, pero tiene las advertencias normales de cableado automático.) Además de esto, Spring admite @Value
para establecer valores directamente en campos miembros desde propiedades, etc.
Sin embargo, Spring no permite que las propiedades se configuren directamente en campos miembros (sin conexión automática).
Mi pregunta es: ¿por qué?
Obviamente es capaz de hacerlo, entonces ¿por qué no? ¿Hay algún efecto secundario negativo que impida esto? ¿O es la capacidad de alguna manera limitada, de modo que solo el cableado automático tenga sentido? ¿Necesita algunos hacks más grandes que llamar setters?
Tenga en cuenta que no deseo discutir los méritos relativos de tener setters y getters en general, solo las razones por las que Spring ha hecho esta elección.
Admite esto a través de la anotación JSR-250 @Resource (en Spring 3.0+)
Personalmente, prefiero esto a la inyección del fijador, y tengo sentimientos encontrados al considerar la inyección del constructor. Aquí están las consideraciones que he pensado sobre FWIW:
1) La inyección del constructor es una buena manera de auto-documentar sus dependencias de frijoles (pro) pero crea muchas infracciones DRY: (a) campo privado, (b) argumento del constructor, (c) código del constructor para establecer el campo desde el parámetro , (d) el código adicional en la configuración del bean (ya sea en las clases de configuración o en xml). Eso es MUCHAS violaciones DRY solo por el bien de la pureza de encapsulación, que ni siquiera me importa. Esto es apenas una violación de la encapsulación, pero crea una gran dependencia en algún contenedor de inyección que respeta las anotaciones JSR-250 (vea a continuación)
2) Crea una dependencia en el contenedor compatible con JSR-250. Tengo sentimientos encontrados sobre esto. Cuando escuché por primera vez acerca de @Resource, lo descarté diciendo que dificultaría la prueba de mi sistema. Sin embargo, terminé usando la primavera en mis pruebas de todos modos. Todavía puedo usar frijoles simulados como lo haría de todos modos, así que nunca fue realmente un problema. Y la pregunta está fuera de las pruebas, ¿cuándo querría volver a utilizar esto? En mi mente, si estás diseñando el sistema para aprovechar un contenedor, abrázalo y úselo. ¿Las violaciones en seco realmente valen la flexibilidad de no correr dentro de un contenedor? Al menos con las anotaciones JSR-250, podría ejecutarse en cualquier entorno JEE6 y obtener la inyección que desee.
3) Puede crear algunos escenarios de depuración no tan buenos si crea una instancia fuera del contenedor: es decir, obtendrá excepciones de puntero nulo en lugar de algo agradable. Esta es una compensación Personalmente creo que no es horrible; quiero decir que si obtienes un NPE en una línea con un @Resource, rápidamente te das cuenta de que no se inyectó.
Creo que encontré la respuesta yo mismo. Fui al código fuente de Spring y vi cómo se implementaron realmente las características. Esto es lo que encontré:
Establecer propiedades a través de XML es probablemente la parte más antigua de Spring, y se basa en gran medida en las clases "java.beans" para la introspección, enumeración de propiedades, etc. Y, obviamente, estas no admiten la introspección de campos. Además de esto, se encuentra la maquinaria de conversión de tipos que determina cómo se puede convertir el valor de la propiedad en un valor adecuado para la propiedad en cuestión. No hay piezas perfectamente separables aquí.
Todas las cosas de @Autowired etc. se implementan en un BeanPostProcessor, que tiene su propio mecanismo de coincidencia de tipos, que no tiene nada que ver con la conversión de tipos. Por eso también se inyecta solo frijoles. Lo mismo prácticamente para @Value, es algo que se resuelve en el lugar y no tiene nada que ver con las propiedades.
Por lo tanto, agregar soporte de inyección de campo, para propiedades en particular, no es un esfuerzo de ingeniería trivial ya que las partes del código que hacen una o la otra están bastante separadas por completo.
Esto no responde exactamente "¿Por qué?", Pero creo que esta es una explicación más convincente de por qué Spring no ha agregado la inyección de dependencia de campo directa que las otras explicaciones que he escuchado. A menos que tengan algo fundamental en contra de eso (lo cual dudo, considerando que quieren permitir la configuración de clases de terceros existentes, no solo de JavaBeans), entonces es solo una cuestión de esfuerzo de ingeniería para obtener la funcionalidad.
La anotación @Autowired utiliza la reflexión para hacer accesibles los campos privados (consulte esta pregunta relacionada ). Puedo ver tres cosas por las que no se usa en los archivos de configuración de Spring.
- Debido a que la configuración se realiza por las propiedades del bean (captadores y definidores), no se puede decir realmente, en el caso probable de que existan, si desea, por ejemplo, llamar a setValue o establecer el valor de miembro.
- Se rompe la encapsulación. Su configuración de Spring no tiene por qué conocer las variables de miembros privados. Con una anotación que está bien, ya que ya está ahí en el código fuente.
- Preocupaciones de seguridad. Un administrador de seguridad más restrictivo podría no permitir que los campos privados sean accesibles a través de la reflexión.