Você está na página 1de 51

Capítulo 3 ■ La introducción de la COI y Di en primavera

com.apress.prospring5.ch3.annotation paquete;

org.springframework.context.annotation.ComponentScan importación;
org.springframework.context.annotation.Configuration importación;

@ComponentScan (basePackages = { "com.apress.prospring5.ch3.annotation"}) @Configuration

HelloWorldConfiguration public class {}

El código para inicializar un ambiente de primavera usando AnnotationConfigApplicationContext trabajará con esta clase también, sin
cambios adicionales.
En las aplicaciones de producción de la vida real, puede haber código heredado, desarrollado con las versiones anteriores de la primavera, o
requisitos podrían ser de tal naturaleza que requiere clases XML y configuración. Afortunadamente, XML y la configuración de Java se pueden mezclar
en más de una forma. Por ejemplo, una clase de configuración puede importar las definiciones de frijol de un archivo XML (o más) usando @ ImportResource,
y el mismo bootstrapping usando AnnotationConfigApplicationContext funcionará en este caso también.

com.apress.prospring5.ch3.mixed paquete;

org.springframework.context.annotation.ComponentScan importación;
org.springframework.context.annotation.Configuration importación;
org.springframework.context.annotation.ImportResource importación;

@ImportResource (ubicaciones = { "ruta de clase: primavera / app-contexto-xml.xml"}) @Configuration

HelloWorldConfiguration public class {}

Por lo tanto, la primavera le permite ser muy creativo en la definición de los granos; usted aprenderá más sobre esto en el capítulo 4 , Que se centra
únicamente en la configuración de la aplicación de primavera.

El uso de inyección Setter

Para configurar la inyección colocador mediante el uso de la configuración de XML, es necesario especificar < propiedad> links debajo de la

<Bean> etiqueta para cada < propiedad> en la que desea inyectar una dependencia. Por ejemplo, para asignar el proveedor de frijol mensaje al messageProvider
propiedad de la messageRenderer frijol, sólo tiene que cambiar el < bean> etiqueta para el renderizador bean, como se muestra en el siguiente fragmento
de código:

<Habas ...>
<Bean id = "renderer"
class => <name = ref = "proveedor"
"com.apress.prospring5.ch2.decoupled.StandardOutMessageRenderer" "messageProvider" propiedad /> </
bean>

<Bean id = "proveedor"
class = "com.apress.prospring5.ch2.decoupled.HelloWorldMessageProvider" /> </ beans>

56
Capítulo 3 ■ La introducción de la COI y Di en primavera

A partir de este código, podemos ver que la proveedor frijol se asigna a la messageProvider propiedad. Se puede utilizar el árbitro atribuir a
asignar una referencia a una propiedad de frijol (discutido en más detalle en breve).
Si está utilizando Primavera 2.5 o posterior y tener la p espacio de nombres declarada en el archivo de configuración XML, se puede declarar la inyección
como se muestra en el siguiente fragmento de código:

<? Xml version = "1.0" encoding = "UTF-8"?>

<habas xmlns = "http://www.springframework.org/schema/beans"


xmlns: xsi = "http://www.w3.org/2001/XMLSchema-instance" xmlns: p =
"http://www.springframework.org/schema/p" xsi: schemaLocation = "http: // www
.springframework.org / esquema / frijoles
http://www.springframework.org/schema/beans/spring-beans.xsd ">

<Bean id = "renderer"
class = "com.apress.prospring5.ch2.decoupled.StandardOutMessageRenderer" t:
messageProvider-ref = "proveedor" />

<Bean id = "proveedor"
class = "com.apress.prospring5.ch2.decoupled.HelloWorldMessageProvider" /> </ beans>

la p espacio de nombres no está definido en un archivo XSD y existe sólo en el núcleo de primavera; Por lo tanto, hay XSD se declara en

el schemaLocation atributo.

Con anotaciones, que es aún más simple. Sólo tiene que añadir un @ Autowired anotación con el método setter, como se muestra en el
siguiente fragmento de código:

com.apress.prospring5.ch3.annotation paquete;
...
org.springframework.beans.factory.annotation.Autowired importación;

@Service ( "renderer")
StandardOutMessageRenderer clase pública implementa MessageRenderer {
...
@ Override
@Autowired
setMessageProvider pública vacío (proveedor de MessageProvider) {
this.messageProvider = proveedor; }}

Dado que declaramos la < Contexto: componente de exploración> etiqueta en el archivo de configuración XML, durante la inicialización de la primavera
de Application Context, Primavera descubrirá los @ Autowired anotaciones y inyectar la dependencia según sea necesario.

57
Capítulo 3 ■ La introducción de la COI y Di en primavera

En lugar de @ Autowired, puedes usar @ Recursos (name = "messageProvider") para lograr el mismo resultado.

@Recurso es una de las anotaciones en el estándar JSR-250 que define un conjunto común de anotaciones Java para su uso en ambas

plataformas JSE y Jee. diferente de @ Autowired, la @ Recurso anotación apoya la nombre

parámetro para más requisitos dI de grano fino. Además, Spring apoya el uso de la @ Inyectar anotación introducida como parte de JSR-299 (Contextos y

la inyección de dependencias para la plataforma Java EE). @ Inyectar es equivalente a la primavera en el comportamiento de @ Autowired anotación.

Para verificar el resultado, puede utilizar DeclareSpringComponents que se presentó anteriormente. Al igual que en el apartado anterior, se
puede intercambiar la App-contexto-xml.xml presentar ante App-contexto-annotation.xml en el código fuente proporcionado para este capítulo, y se
encuentra que ambos casos producen el mismo resultado: “Hello World!” se imprime.

El uso de inyección Constructor

En el ejemplo anterior, el MessageProvider implementación, HelloWorldMessageProvider, devuelto el mismo mensaje codificado para cada llamada de la getMessage
() método. En el archivo de configuración de la primavera, puede crear fácilmente un configurable MessageProvider que permite que el mensaje para ser
definida externamente, como se muestra en el siguiente fragmento de código:

com.apress.prospring5.ch3.xml paquete;

com.apress.prospring5.ch2.decoupled.MessageProvider importación;

ConfigurableMessageProvider clase pública


implementa MessageProvider {
String mensaje privado;

ConfigurableMessageProvider pública (String mensaje) {


this.message = mensaje; }

@Anular
Cadena getMessage pública () {
mensaje de retorno; }}

Como se puede ver, es imposible crear una instancia de ConfigurableMessageProvider sin proporcionar un valor para el mensaje (a menos
que suministre nulo). Esto es exactamente lo que queremos, y esta clase es ideal para su uso con la inyección de constructor. El siguiente
fragmento de código muestra cómo se puede redefinir el
proveedor definición de frijol para crear una instancia de ConfigurableMessageProvider, inyectar el mensaje mediante el uso de inyección de constructor:

<habas xmlns = "http://www.springframework.org/schema/beans"


xmlns: xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi: schemaLocation =
"http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd ">

<Bean id = "messageProvider"

58
Capítulo 3 ■ La introducción de la COI y Di en primavera

class = "com.apress.prospring5.ch3.xml.ConfigurableMessageProvider"> <constructor-arg value =


"Espero que alguien reciba mi mensaje en una botella" /> </ bean> </ beans>

En este código, en lugar de utilizar un < propiedad> tag, se utilizó un < constructor-arg> etiqueta. Debido a que no estamos de paso en otro
grano de este tiempo, sólo una Cuerda literal, se utiliza el valor en lugar de atribuir árbitro para especificar el valor para el argumento del
constructor. Al tener más de un argumento del constructor o de su clase tiene más de un constructor, es necesario dar a cada < constructor-arg> etiquetar
un atributo de índice para especificar el índice del argumento, comenzando en 0, en la firma constructora. Siempre es mejor utilizar el atributo de
índice cada vez que se trata de constructores que tienen varios argumentos, para evitar la confusión entre los parámetros y asegurarse de que la
primavera recoge el constructor correcto.

Además de pag espacio de nombres, a partir de la primavera 3.1, también se puede utilizar el do espacio de nombres, como se muestra aquí:

<habas xmlns = "http://www.springframework.org/schema/beans"


xmlns: xsi = "http://www.w3.org/2001/XMLSchema-instance" xmlns: c =
"http://www.springframework.org/schema/c" xsi: schemaLocation = "http: // www
.springframework.org / esquema / habas
http://www.springframework.org/schema/beans/spring-beans.xsd ">

<Bean id = "proveedor"
class = "com.apress.prospring5.ch3.xml.ConfigurableMessageProvider" c: message =
"Espero que alguien reciba mi mensaje en una botella" /> </ beans>

la do espacio de nombres no está definido en un archivo XSD tampoco y sólo existe en el resorte del núcleo; Por lo tanto, hay XSD se declara en

el schemaLocation atributo.

Para utilizar una anotación para la inyección de constructor, también utilizamos el @ Autowired anotación en el método constructor del bean de
destino, que es una opción alternativa a la inyección usando setter, como se muestra en el siguiente fragmento de código:

com.apress.prospring5.ch3.annotated paquete;

com.apress.prospring5.ch2.decoupled.MessageProvider importación;
org.springframework.beans.factory.annotation.Autowired importación;
org.springframework.stereotype.Service importación;

@Proveedor de servicio")
ConfigurableMessageProvider clase pública implementa MessageProvider {

String mensaje privado;

@Autowired
ConfigurableMessageProvider pública (
(( "Mensaje configurable") String mensaje @Valor) {
this.message = mensaje; }

59
Capítulo 3 ■ La introducción de la COI y Di en primavera

@Anular
Cadena getMessage pública () {
volver this.message; }}

A partir del código anterior, podemos ver que usamos otra anotación, @ Valor, para definir el valor a ser inyectado en el constructor. Esta es la
manera en la primavera inyectamos valores en un grano. Además de cadenas simples, podemos utilizar la poderosa SpEL para el valor de inyección
dinámica (más sobre esto más adelante en este capítulo).
Sin embargo, difíciles de codificar el valor en el código no es una buena idea; para cambiarlo, sería necesario volver a compilar el programa. Incluso si
decide DI-estilo de anotación, una buena práctica consiste en exteriorizar esos valores para inyección. Exteriorizar el mensaje, vamos a definir el mensaje como
un grano de primavera en el archivo de configuración de anotación, como se muestra en el siguiente fragmento de código:

<Habas ...>
<Context: componente-scan
base paquete = "com.apress.prospring5.ch3.annotated" />

<Bean id = "mensaje" class = "java.lang.String"


c: _0 = "Espero que alguien reciba mi mensaje en una botella" /> </ beans>

Aquí definimos un grano con un ID de mensaje y el tipo de java.lang.String. Tenga en cuenta que también utilizamos la
do espacio de nombres para la inyección de constructor para establecer el valor de la cadena, y _ 0 indica el índice para el argumento del constructor. Tener
el frijol declaró, podemos quitar el @ Valor anotación de la haba de destino, como se muestra en el siguiente fragmento de código:

com.apress.prospring5.ch3.annotated paquete;

com.apress.prospring5.ch2.decoupled.MessageProvider importación;
org.springframework.beans.factory.annotation.Autowired importación;
org.springframework.stereotype.Service importación;

@Proveedor de servicio")
ConfigurableMessageProvider clase pública implementa MessageProvider {

String mensaje privado;

@Autowired
ConfigurableMessageProvider pública (String mensaje) {
this.message = mensaje; }

@Anular
Cadena getMessage pública () {
volver this.message; }}

60
Capítulo 3 ■ La introducción de la COI y Di en primavera

Desde declaramos que el grano de mensaje y su ID son los mismos que el nombre del argumento especificado en el constructor,
Spring detectará la anotación e inyectar el valor en el método constructor. Ahora ejecute la prueba usando el siguiente código en contra
tanto el XML ( app-context.xml.xml) y configuraciones de anotación ( app-contexto-annotation.xml), y el mensaje configurado se mostrará
en ambos casos:

com.apress.prospring5.ch3 paquete;

com.apress.prospring5.ch2.decoupled.MessageProvider importación;
org.springframework.context.support.GenericXmlApplicationContext importación;

DeclareSpringComponents clase pública {


public void (String ... args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext (); ctx.load ( "ruta de
clase: primavera / app-contexto-annotation.xml"); ctx.refresh ();

MessageProvider messageProvider = ctx.getBean ( "proveedor",


MessageProvider.class);

System.out.println (messageProvider.getMessage ()); }}

En algunos casos, la primavera le resulta imposible decir qué constructor queremos que se utilice para la inyección de constructor. Esto por lo general
se presenta cuando tenemos dos constructores con el mismo número de argumentos y de los tipos utilizados en los argumentos están representados de la
misma manera. Considere el siguiente código:

com.apress.prospring5.ch3.xml paquete;

org.springframework.context.support.GenericXmlApplicationContext importación;

ConstructorConfusion public class {


someValue cadena privada;

ConstructorConfusion pública (String someValue) {


System.out.println ( "ConstructorConfusion (String) llamada"); this.someValue =
someValue; }

ConstructorConfusion pública (int someValue) {


System.out.println ( "ConstructorConfusion (int) llama"); this.someValue =
"Número:" + Integer.toString (someValue); }

public String toString () {


volver someValue; }

public void (String ... args) {


GenericXmlApplicationContext ctx = new GenericXmlApplicationContext (); ctx.load ( "ruta de
clase: primavera / app-contexto-xml.xml"); ctx.refresh ();

61
Capítulo 3 ■ La introducción de la COI y Di en primavera

ConstructorConfusion cc = (ConstructorConfusion)
ctx.getBean ( "constructorConfusion");
System.out.println (cc); ctx.close}}

Esto simplemente recupera un grano de tipo ConstructorConfusion desde Application Context y escribe el valor a la consola de salida.
Ahora mira el siguiente código de configuración:

<Habas ...>
<Bean id = "proveedor"
class = "com.apress.prospring5.ch3.xml.ConfigurableMessageProvider" c: message =
"Espero que alguien reciba mi mensaje en una botella" />

<Bean id = "constructorConfusion"
class = "com.apress.prospring5.ch3.xml.ConstructorConfusion"> <constructor-arg>

<Valor> 90 </ value> </


constructor-arg> </ bean>

</ Beans>

¿Cuál de los constructores se llama en este caso? Ejecutar el ejemplo se obtiene el resultado siguiente:

ConstructorConfusion (String) llamada

Esto demuestra que el constructor con la Cuerda argumento se llama. Este no es el efecto deseado, ya que queremos prefijo cualquier valor entero
pasado en mediante el uso de inyección de constructor con Número:, como se muestra en la
En t constructor. Para evitar esto, hay que hacer una pequeña modificación en la configuración, como se muestra en el siguiente fragmento de código:

<Habas ...>
<Bean id = "proveedor"
class = "com.apress.prospring5.ch3.xml.ConfigurableMessageProvider" c: message =
"Espero que alguien reciba mi mensaje en una botella" />

<Bean id = "constructorConfusion"
class = "com.apress.prospring5.ch3.xml.ConstructorConfusion"> <constructor-arg
tipo = "int">
<Valor> 90 </ value> </
constructor-arg> </ bean>

</ Beans>

Aviso ahora que el < constructor-arg> etiqueta tiene un atributo adicional, tipo, que especifica el tipo de argumento resorte debe
buscar. Ejecutar el ejemplo de nuevo con la configuración corregido produce la salida correcta.

ConstructorConfusion (int) llamado Número:


90

62
Capítulo 3 ■ La introducción de la COI y Di en primavera

Para la inyección de la construcción de estilo de anotación, la confusión se puede evitar mediante la aplicación de la anotación directamente al método

constructor de destino, como se muestra en el siguiente fragmento de código:

com.apress.prospring5.ch3.annotated paquete;

org.springframework.beans.factory.annotation.Autowired importación;
org.springframework.beans.factory.annotation.Value importación;
org.springframework.context.support.GenericXmlApplicationContext importación;
org.springframework.stereotype.Service importación;

@Service ( "constructorConfusion") public class


{ConstructorConfusion

someValue cadena privada;

ConstructorConfusion pública (String someValue) {


System.out.println ( "ConstructorConfusion (String) llamada"); this.someValue =
someValue; }

@Autowired
ConstructorConfusion pública (@Valor ( "90") int someValue) {
System.out.println ( "ConstructorConfusion (int) llama"); this.someValue =
"Número:" + Integer.toString (someValue); }

public String toString () {


volver someValue; }

public void (String ... args) {


GenericXmlApplicationContext ctx = new GenericXmlApplicationContext (); ctx.load ( "ruta de
clase: primavera / app-contexto-annotation.xml"); ctx.refresh ();

ConstructorConfusion cc = (ConstructorConfusion)
ctx.getBean ( "constructorConfusion");
System.out.println (cc); ctx.close (); }}

Mediante la aplicación de la @ Autowired anotación para el método constructor deseado, Spring utilizará ese método para instanciar el bean e
inyectar el valor como se especifica. Al igual que antes, debemos exteriorizar el valor de la configuración.

la @ Autowired anotación se puede aplicar a solamente uno de los métodos constructor. Si aplicamos la anotación a más de un

método constructor, la primavera se quejará mientras bootstrapping Application Context.

63
Capítulo 3 ■ La introducción de la COI y Di en primavera

El uso de inyección Campo

Hay un tercer tipo de inyección de dependencias apoyado en la primavera de llamada inyección de campo. Como su nombre lo dice, la
dependencia se inyecta directamente en el campo, con ningún constructor o colocador necesario. Esto se realiza anotando el miembro de la clase
con el Autowired anotación. Esto puede parecer práctico, porque cuando la dependencia no es necesaria fuera del objeto que es parte de, alivia el
desarrollador de escribir un código que ya no se usa después de la creación inicial del grano. En el siguiente fragmento de código, el grano de
tipo Cantante tiene un campo de tipo Inspiración:

com.apress.prospring5.ch3.annotated paquete;

org.springframework.beans.factory.annotation.Autowired importación;
org.springframework.stereotype.Service importación;

@Service ( "cantante") Singer


public class {

@Autowired
inspirationBean inspiración privada;

public void cantar () {


System.out.println ( "..." + inspirationBean.getLyric ()); }}

El campo es privado, pero el contenedor primavera COI no le importa realmente en eso; que utiliza la reflexión para poblar la dependencia
requerida. los Inspiración código de clase se muestra aquí; es un grano simple con una
Cuerda miembro:

com.apress.prospring5.ch3.annotated paquete;

org.springframework.beans.factory.annotation.Value importación;
org.springframework.stereotype.Component importación;

@Componente

La inspiración public class {

Cadena lírica privada =


"Puedo mantener la puerta entreabierta, para dejar pasar la luz";

La inspiración pública (
@Value ( "Para toda mi carrera, puedo entender") lírica String) {this.lyric = lírica; }

Cadena getLyric pública () {


letra regresar; }

setLyric pública vacío (letra String) {


this.lyric = letra; }}

64
Capítulo 3 ■ La introducción de la COI y Di en primavera

La siguiente configuración utiliza la exploración componente para descubrir las definiciones de frijol que serán creados por el contenedor del
resorte IoC:

<Habas ...>
<Context: componente-scan
base paquete = "com.apress.prospring5.ch3.annotated" />
</ Beans>

Encontrar un grano de tipo Inspiración, el contenedor del resorte IoC inyectará que bean en el
inspirationBean miembro de cantante frijol. Es por eso que cuando se ejecuta el ejemplo representado en el siguiente fragmento de código, “Para
toda mi carrera, puedo entender” se imprimirá en la consola.

com.apress.prospring5.ch3.annotated paquete;

org.springframework.context.support.GenericXmlApplicationContext importación;

FieldInjection public class {

public void (String ... args) {

GenericXmlApplicationContext ctx =
nuevo GenericXmlApplicationContext (); ctx.load ( "ruta
de clase: primavera / app-context.xml"); ctx.refresh ();

Cantante singerBean = ctx.getBean (Singer.class);


singerBean.sing ();

ctx.close (); }}

Pero también hay desventajas, y es por eso usar la inyección de campo se suele evitarse.

• Aunque es fácil de agregar dependencias de esta manera, hay que tener cuidado de no violar el principio de la responsabilidad

individual. Tener más dependencias significa más responsabilidades de una clase, que podría conducir a una dificultad de separar las

preocupaciones en el tiempo de refactorización. La situación en la que una clase se convierte en hinchada es más fácil de ver cuando

dependencias se establecen con constructores o fijadores pero está bastante bien ocultos cuando se utiliza la inyección de campo.

• La responsabilidad de dependencias inyectables se pasa al recipiente en la primavera, pero la clase debe


comunicar claramente el tipo de dependencias necesarias utilizando una interfaz pública, a través de métodos o
constructores. El uso de inyecciones de campo, puede convertirse en claro qué tipo de dependencia es realmente
necesario y si la dependencia es obligatorio o no.

• inyección campo presenta una dependencia del recipiente Spring, como el @ Autowired
anotación es un componente de primavera; Por lo tanto, el grano ya no es un POJO y no puede ser instanciada
independientemente.

• inyección de campo no puede ser utilizado para los campos finales. Este tipo de campos sólo se puede inicializar mediante la inyección de

constructor.

• El campo de inyección presenta dificultades a la hora de escribir pruebas como las dependencias tienen que inyectarse manualmente.

sesenta y cinco
Capítulo 3 ■ La introducción de la COI y Di en primavera

El uso de parámetros de inyección

En los tres ejemplos anteriores, que vio cómo inyectar otros componentes y valores en un grano mediante el uso tanto de la inyección de la moda y la inyección
de constructor. Primavera es compatible con una gran variedad de opciones para los parámetros de inyección, lo que le permite no sólo inyecta otros
componentes y valores simples, sino también colecciones de Java, propiedades definidas externamente, e incluso los frijoles en otra fábrica. Puede utilizar todos
estos tipos de parámetros de inyección tanto para la inyección de la inyección y constructor setter utilizando la etiqueta correspondiente en la < propiedad> y

<constructor-args> etiquetas, respectivamente.

La inyección de valores simples

La inyección de valores simples en sus granos es fácil. Para ello, basta con especificar el valor de la etiqueta de configuración, envuelto dentro de un < valor> etiqueta.
Por defecto, no sólo puede el < valor> leer la etiqueta Cuerda valores, pero también puede convertir estos valores a cualquier clase de contenedor primitiva o
primitivas. El siguiente fragmento de código muestra un grano simple que tiene una variedad de propiedades expuestas para inyección:

com.apress.prospring5.ch3.xml paquete;

org.springframework.context.support.GenericXmlApplicationContext importación;

InjectSimple public class {

private String nombre; int edad privada;


altura del flotador privado; programador
private boolean; ageInSeconds largas
privadas;

public void (String ... args) {


GenericXmlApplicationContext ctx =
nuevo GenericXmlApplicationContext (); ctx.load ( "ruta de clase:
primavera / app-contexto-xml.xml"); ctx.refresh ();

InjectSimple = simples (InjectSimple) ctx.getBean ( "injectSimple"); System.out.println


(simple); ctx.close (); }

setAgeInSeconds public void () {largo ageInSeconds


this.ageInSeconds = ageInSeconds; }

setProgrammer public void (programador booleano) {


this.programmer = programador; }

setAge pública vacío (int edad) {


this.age = edad; }

66
Capítulo 3 ■ La introducción de la COI y Di en primavera

setHeight pública vacío (altura del flotador) {


this.height = altura; }

pública setName void (String nombre) {


this.name = nombre; }

public String toString () {


volver "Nombre:" + nombre + "\ n"
+ "Edad:" + edad + "\ n"
+ "La edad en segundos:" + ageInSeconds + "\ n"
+ "Altura:" + alto + "\ n"
+ "¿Es programador ?:" + programador;
}}

Además de las propiedades, el InjectSimple clase también define la principal() método que crea una
contexto de aplicación y a continuación, recupera una InjectSimple frijol de primavera. Los valores de las propiedades de este frijol se escriben en la
salida de la consola. La configuración contenida en App-contexto-xml.xml para este bean se representa en el siguiente fragmento:

<Habas ...>

<Bean id = "injectSimpleConfig"
class = "com.apress.prospring5.ch3.xml.InjectSimpleConfig" />

<Bean id = "injectSimpleSpel"
class = "com.apress.prospring5.ch3.xml.InjectSimpleSpel" t: name = "John
Mayer" t: edad = "39" t: height = "1.92" t: programador = "false" p: ageInSeconds =
"1241401112 "/> </ beans>

Se puede ver a partir de los dos fragmentos de código anteriores que es posible definir propiedades en el bean que aceptan Cuerda valores, valores
primitivos, o valores de envoltura primitivas y luego inyectar valores de estas propiedades mediante el uso de la < valor> etiqueta. Aquí está la salida creado
mediante la ejecución de este ejemplo como se esperaba:

Nombre: John Mayer


Edad: 39
Edad en segundos: 1241401112
Altura: 1,92
Programador es falsa ?:

67
Capítulo 3 ■ La introducción de la COI y Di en primavera

Para la inyección de valor simple de estilo de anotación, podemos aplicar el @ Valor anotación a las propiedades de frijol. Esta vez, en lugar del método de
selección, se aplica la anotación a la declaración de declaración de propiedad, como podemos ver en el siguiente fragmento de código (primavera es compatible
con la anotación, ya sea en el método de selección o en las propiedades):

com.apress.prospring5.ch3.annotated paquete;

org.springframework.beans.factory.annotation.Value importación;
org.springframework.context.support.GenericXmlApplicationContext importación;
org.springframework.stereotype.Service importación;

@Service ( "") injectSimple


InjectSimple clase pública {

@Value ( "John Mayer") private


String nombre; @Value ( "39")
int edad privada; @Value (
"1,92") altura del flotador
privado; @Valor ( "falso")

programador private boolean; @Value (


"1241401112") ageInSeconds largas
privadas;

public void (String ... args) {


GenericXmlApplicationContext ctx =
nuevo GenericXmlApplicationContext ();
ctx.load ( "ruta de clase: primavera / app-contexto-annotation.xml"); ctx.refresh ();

InjectSimple = simples (InjectSimple) ctx.getBean ( "injectSimple"); System.out.println


(simple);

ctx.close (); }

public String toString () {


volver "Nombre:" + nombre + "\ n"
+ "Edad:" + edad + "\ n"
+ "La edad en segundos:" + ageInSeconds + "\ n"
+ "Altura:" + alto + "\ n"
+ "¿Es programador ?:" + programador;
}}

Con ello se consigue el mismo resultado que la configuración XML.

68
Capítulo 3 ■ La introducción de la COI y Di en primavera

La inyección de valores usando SpEL

Una característica de gran alcance introducido en la primavera 3 es el Lenguaje de Expresión primavera (SpEL). SpEL le permite evaluar una expresión
dinámica y luego lo utiliza en la primavera de Application Context. Puede utilizar el resultado para la inyección en los granos de la primavera. En esta
sección, echar un vistazo a cómo utilizar SpEL para inyectar propiedades de otros granos, utilizando el ejemplo de la sección anterior.

Supongamos ahora queremos exteriorizar los valores para ser inyectado en un grano de resorte en una clase de configuración, como se muestra en el siguiente

fragmento de código:

com.apress.prospring5.ch3.annotated paquete;

org.springframework.stereotype.Component importación;

@Component ( "injectSimpleConfig") public


class {InjectSimpleConfig

private String nombre = "John Mayer"; edad private int = 39;


altura del flotador privado = 1.92f; boolean programador
privado = false; ageInSeconds largas privadas =
1_241_401_112L;

Public String getName () {


Nombre del retorno; }

public int getAge () {


la edad de retorno; }

getHeight flotación pública () {


altura de retorno; }

isProgrammer public boolean () {


programador de retorno; }

getAgeInSeconds largas públicos () {


ageInSeconds regresar; }}

Podemos entonces definir el grano en la configuración XML y utilizar SpEL para inyectar las propiedades del bean en el grano dependiente, como se
muestra en el siguiente fragmento de configuración:

<Habas ...>

<Bean id = "injectSimpleConfig"
class = "com.apress.prospring5.ch3.xml.InjectSimpleConfig" />

69
Capítulo 3 ■ La introducción de la COI y Di en primavera

<Bean id = "injectSimpleSpel"
class = "com.apress.prospring5.ch3.xml.InjectSimpleSpel" t: name = "# {}
injectSimpleConfig.name" t: edad = "# {injectSimpleConfig.age + 1}" t: height =
"# {injectSimpleConfig. altura}" t: programador = "# {}
injectSimpleConfig.programmer" p: ageInSeconds = "#
{injectSimpleConfig.ageInSeconds}"/> </ beans>

Tenga en cuenta que usamos el SpEL # { injectSimpleConfig.name} en referencia a la propiedad de la otra frijol. Para la edad, añadimos 1 al
valor del grano para indicar que podemos utilizar para manipular SpEL la propiedad como mejor nos parezca y lo inyecta en el grano dependiente.
Ahora podemos probar la configuración con el programa que se muestra en el siguiente fragmento de código:

com.apress.prospring5.ch3.xml paquete;

org.springframework.context.support.GenericXmlApplicationContext importación;

public class {InjectSimpleSpel


private String nombre; int edad privada;
altura del flotador privado; programador
private boolean; ageInSeconds largas
privadas;

Public String getName () {


volver this.name; }

pública setName void (String nombre) {


this.name = nombre; }

public int getAge () {


volver this.age; }

setAge pública vacío (int edad) {


this.age = edad; }

getHeight flotación pública () {


volver this.height; }

setHeight pública vacío (altura del flotador) {


this.height = altura; }

isProgrammer public boolean () {


volver this.programmer; }

70
Capítulo 3 ■ La introducción de la COI y Di en primavera

setProgrammer public void (programador booleano) {


this.programmer = programador; }

getAgeInSeconds largas públicos () {


this.ageInSeconds regresar; }

setAgeInSeconds public void () {largo ageInSeconds


this.ageInSeconds = ageInSeconds; }

public String toString () {


volver "Nombre:" + nombre + "\ n"
+ "Edad:" + edad + "\ n"
+ "La edad en segundos:" + ageInSeconds + "\ n"
+ "Altura:" + alto + "\ n"
+ "¿Es programador ?:" + programador; }

public void (String ... args) {


GenericXmlApplicationContext ctx = new GenericXmlApplicationContext (); ctx.load ( "ruta de
clase: primavera / app-contexto-xml.xml"); ctx.refresh ();

InjectSimpleSpel = simples (InjectSimpleSpel) ctx.getBean ( "injectSimpleSpel"); System.out.println


(simple);

ctx.close (); }}

La siguiente es la salida del programa:

Nombre: John Mayer


Edad: 40
Edad en segundos: 1241401112
Altura: 1,92
Programador es falsa ?:

Cuando se utiliza la inyección valor de estilo de anotación, sólo tenemos que sustituir las anotaciones de valor con las expresiones juego (ver el
siguiente fragmento de código):

com.apress.prospring5.ch3.annotated paquete;

org.springframework.beans.factory.annotation.Value importación;
org.springframework.context.support.GenericXmlApplicationContext importación;
org.springframework.stereotype.Service importación;

@Service ( "injectSimpleSpel") public class


{InjectSimpleSpel

71
Capítulo 3 ■ La introducción de la COI y Di en primavera

@Value ( "# {} injectSimpleConfig.name") private


String nombre;

@Value ( "# {injectSimpleConfig.age + 1}") int edad


privada;

@Value ( "# {} injectSimpleConfig.height") altura del


flotador privado;

@Value ( "# {} injectSimpleConfig.programmer")


programador private boolean;

@Value ( "# {} injectSimpleConfig.ageInSeconds")


ageInSeconds largas privadas;

public String toString () {


volver "Nombre:" + nombre + "\ n"
+ "Edad:" + edad + "\ n"
+ "La edad en segundos:" + ageInSeconds + "\ n"
+ "Altura:" + alto + "\ n"
+ "¿Es programador ?:" + programador; }

public void (String ... args) {


GenericXmlApplicationContext ctx = new GenericXmlApplicationContext (); ctx.load ( "ruta de
clase: primavera / app-contexto-annotation.xml"); ctx.refresh ();

InjectSimpleSpel = simples (InjectSimpleSpel) ctx.getBean ( "injectSimpleSpel"); System.out.println


(simple);

ctx.close (); }}

La versión de InjectSimpleConfig se muestra a continuación:

com.apress.prospring5.ch3.annotated paquete;

org.springframework.stereotype.Component importación;

@Component ( "injectSimpleConfig") public


class {InjectSimpleConfig
private String nombre = "John Mayer"; edad private int = 39;
altura del flotador privado = 1.92f; boolean programador
privado = false; ageInSeconds largas privadas =
1_241_401_112L;

// captadores aquí ...}

72
Capítulo 3 ■ La introducción de la COI y Di en primavera

En el fragmento anterior, en lugar de la @ anotación de servicio, @Component se utilizó. Básicamente, el uso


@Componente tiene el mismo efecto que @ Servicio. Ambas anotaciones están instruyendo del resorte que la clase comentada es un candidato para la detección
automática utilizando la configuración basada en anotación y escaneo ruta de clase. Sin embargo, dado que la InjectSimpleConfig clase es el almacenamiento de la
configuración de la aplicación, en lugar de proporcionar un servicio de negocio, utilizando @ Componente tiene más sentido. Prácticamente, @ Servicio es una
especialización de @ Componente, lo que indica que la clase anotada está proporcionando un servicio de negocio a otras capas dentro de la aplicación.

Probando el programa producirá el mismo resultado. Usando SpEL, se puede acceder a los frijoles y las propiedades del muelle gestionados y manipularlos
para el uso de la aplicación por el apoyo de las características del lenguaje sofisticados y la sintaxis de la primavera.

La inyección de frijoles en la Unidad de XML Mismo

Como ya se ha visto, es posible inyectar un grano a otro mediante el uso de la árbitro etiqueta. El siguiente fragmento de código muestra una clase que
expone una setter para permitir que un grano a inyectar:

com.apress.prospring5.ch3.xml paquete;

org.springframework.context.support.GenericXmlApplicationContext importación;
com.apress.prospring5.ch3.Oracle importación;

InjectRef public class {


Oracle Oracle privado;

setOracle pública vacío (Oracle Oracle) {


this.oracle = oráculo; }

public void (String ... args) {


GenericXmlApplicationContext ctx = new GenericXmlApplicationContext (); ctx.load ( "ruta de
clase: primavera / app-contexto-xml.xml"); ctx.refresh ();

InjectRef injectRef = (InjectRef) ctx.getBean ( "injectRef"); System.out.println


(injectRef);

ctx.close (); }

public String toString () {


oracle.defineMeaningOfLife retorno (); }}

Para configurar la primavera para inyectar un grano a otro, primero tiene que configurar dos granos: uno que será inyectada y uno a ser el blanco de
la inyección. Una vez hecho esto, sólo tiene que configurar la inyección mediante el uso de la etiqueta < ref> etiqueta en el grano de destino. El siguiente
fragmento de código muestra un ejemplo de esta configuración (archivo app-contexto-xml.xml):

<Habas ...>

<Bean id = "oráculo" name = "wiseworm"


class = "com.apress.prospring5.ch3.BookwormOracle" />

73
Capítulo 3 ■ La introducción de la COI y Di en primavera

<Bean id = "injectRef"
class = "com.apress.prospring5.ch3.xml.InjectRef"> <property name
= "oráculo">
<Ref frijol = "oráculo" /> </
property> </ bean> </ beans>

Ejecución de la InjectRef clase produce el siguiente resultado:

Las enciclopedias son un desperdicio de dinero - ir a ver el mundo en vez

Un punto importante a destacar es que el tipo que se inyecta no tiene que ser el tipo exacto definido en el objetivo; los tipos sólo
tienen que ser compatibles. Compatible significa que si el tipo declarado en el objetivo es una interfaz, el tipo inyectado debe implementar
esta interfaz. Si el tipo declarado es una clase, el tipo inyectado debe ser ya sea del mismo tipo o un subtipo. En este ejemplo, la InjectRef clase
define la setOracle ()
método para recibir una instancia de Oráculo, que es una interfaz, y el tipo inyectado es BookwormOracle, una clase que implementa Oráculo. Este es un punto que
causa confusión para algunos desarrolladores, pero en realidad es bastante simple. Inyección está sujeto a las mismas reglas de escritura que cualquier código Java,
por lo que el tiempo que usted está familiarizado con la forma de escribir obras de Java, la comprensión de la tipificación de la inyección es fácil.

En el ejemplo anterior, el ID del grano para inyectar se especifica mediante el atributo local de la
<Ref> etiqueta. Como se verá más adelante, en la sección “La comprensión de la haba de nombres”, se puede dar un grano más de un nombre para que pueda
referirse a ella usando una variedad de alias. Cuando se utiliza el atributo local, significa que el < ref> la etiqueta sólo se basa en la identificación del frijol y nunca
en cualquiera de sus alias. Por otra parte, la definición de frijol debe existir en el mismo archivo de configuración XML. Para inyectar un grano por cualquier
nombre o importar uno de los otros archivos de configuración XML, utilice el atributo de frijol de la < ref> etiquetar en lugar del atributo local. El siguiente fragmento
de código se muestra una configuración alternativa para el ejemplo anterior, el uso de un nombre alternativo para el bean inyectada:

<Habas ...>

<Bean id = "oráculo" name = "wiseworm"


class = "com.apress.prospring5.ch3.BookwormOracle" />

<Bean id = "injectRef"
class = "com.apress.prospring5.ch3.xml.InjectRef"> <property name
= "oráculo">
<Ref frijol = "wiseworm" /> </
property> </ bean> </ beans>

En este ejemplo, la oráculo bean se da un alias mediante el uso de la nombre atributo, y luego se inyecta en el injectRef bean mediante el uso de
este alias en conjunción con el atributo de frijol de la < ref> etiqueta. No se preocupe demasiado acerca de la semántica de nombres en este momento.
Discutimos esto en mucho más detalle más adelante en el capítulo. Ejecución de la InjectRef clase otra vez produce el mismo resultado que el ejemplo
anterior.

74
Capítulo 3 ■ La introducción de la COI y Di en primavera

Inyección y Application Context de anidamiento

Hasta ahora, los granos que han sido la inyección se han localizado en el mismo Application Context ( y por lo tanto la misma BeanFactory) como los
granos que se inyectan en. Sin embargo, Spring soporta una estructura jerárquica para
Application Context de modo que uno de contexto (y por lo tanto el asociar BeanFactory) se considera el padre de otro. Al permitir ApplicationContexts a
anidar, Primavera le permite dividir la configuración en diferentes archivos, que es un regalo del cielo en proyectos más grandes con una gran
cantidad de granos.
Al anidar Application Context casos, Primavera permite frijoles en lo que se considera el contexto niño para hacer referencia a los granos en el
contexto de los padres. Application Context anidación usando GenericXmlApplicationContext
es sencillo de entender. Para anidar una GenericXmlApplicationContext dentro de otro, simplemente llame al
setParent () método en el que el niño Application Context, como se muestra en el siguiente ejemplo de código:

com.apress.prospring5.ch3 paquete;

org.springframework.context.support.GenericXmlApplicationContext importación;

HierarchicalAppContextUsage public class {

public void (String ... args) {


GenericXmlApplicationContext padres = new GenericXmlApplicationContext (); parent.load ( "ruta de
clases: primavera / padre-context.xml"); parent.refresh ();

GenericXmlApplicationContext niño = new GenericXmlApplicationContext (); child.load ( "ruta de


clase: primavera / niño-context.xml"); child.setParent (padre); child.refresh ();

Canción song1 = (Song) child.getBean ( "song1"); Canción


song2 = (Song) child.getBean ( "song2"); Canción Song3 =
(Song) child.getBean ( "Song3");

System.out.println ( "de CTX padre:" + song1.getTitle ()); System.out.println ( "de


ctx niño:" + song2.getTitle ()); System.out.println ( "de CTX padre:" + song3.getTitle
());

child.close ();
parent.close (); }}

los Canción clase es bastante simple, y se muestra aquí:

com.apress.prospring5.ch3 paquete;

Canción public class {


String título privado;

pública setTitle void (String title) {


this.title = título; }

75
Capítulo 3 ■ La introducción de la COI y Di en primavera

Cadena getTitle pública () {


Título de retorno; }}

Dentro del archivo de configuración para el niño Application Context, hace referencia a un frijol en el padre
Application Context funciona exactamente igual que hace referencia a un grano en el niño Application Context, a menos que tenga un grano en el
niño Application Context que comparte el mismo nombre. En ese caso, sólo tiene que reemplazar el atributo del frijol árbitro con elemento padre, y
usted está en su camino. El siguiente fragmento de configuración muestra el contenido del archivo de configuración para el padre BeanFactory, llamado
padre-context.xml:

<Habas ...>
<Bean id = clase "childTitle" = "java.lang.String" c: _0 = "hijas" />

<Bean id = clase "parentTitle" = "java.lang.String" c: _0 = "Gravity" /> </ beans>

Como se puede ver, esta configuración simplemente define dos granos: childTitle y parentTitle. Ambos son
Cuerda los objetos con los valores hijas y Gravedad. El siguiente fragmento de configuración representa la configuración para el
niño Application Context que está contenida en niño-context.xml:

<Habas ...>

<Bean id = clase "song1" = "com.apress.prospring5.ch3.Song"


t: título-ref = "parentTitle" />

<Bean id = clase "song2" = "com.apress.prospring5.ch3.Song"


t: título-ref = "childTitle" />

<Bean id = clase "Song3" = "com.apress.prospring5.ch3.Song">


<Property name = "title">
<Parent ref = "childTitle" /> </
property> </ bean>

<Bean id = clase "childTitle" = "java.lang.String" c: _0 = "No hay tal cosa" /> </ beans>

Tenga en cuenta que hemos definido cuatro granos de aquí. childTitle en este código es similar a childTitle en el padre, excepto que el Cuerda
que representa tiene un valor diferente, lo que indica que se encuentra en el niño
Application Context.
los song1 bean está utilizando el bean árbitro atribuir a hacer referencia al bean llamado parentTitle. Debido a que este frijol sólo existe en la
matriz BeanFactory, song1 recibe una referencia a ese bean. Hay dos puntos de interés aquí. En primer lugar, puede utilizar el atributo de frijol para
hacer referencia a los granos, tanto en el niño y el padre
Application Context s. Esto hace que sea fácil hacer referencia a los granos de forma transparente, lo que le permite moverse entre los granos de archivos de
configuración como su aplicación crece. El segundo punto de interés es que no se puede utilizar el atributo local para referirse a los frijoles en la matriz Application
Context. Los cheques de intérprete XML para ver que el valor del atributo local, existe como un elemento válido en el mismo archivo, evitando que pueda ser
utilizado para hacer referencia a los granos en el contexto de los padres.

76

www.allitebooks.com
Capítulo 3 ■ La introducción de la COI y Di en primavera

los song2 bean está utilizando el bean árbitro atributo para hacer referencia a childTitle. Debido a que el frijol se define en tanto Application
Context s, la song2 bean recibe una referencia a childTitle en su propia
Application Context.
los Song3 bean está utilizando el < ref> etiqueta para referencia childTitle directamente en la matriz
Application Context. Porque Song3 está utilizando el atributo padre de la < ref> etiqueta, el childTitle instancia declaró en el niño Application
Context se ignora por completo.

Usted puede haber notado que, a diferencia song1 y song2, la Song3 frijol no está utilizando el pag espacio de nombres. Mientras que la pag espacio

de nombres proporciona atajos útiles, que no proporciona todas las capacidades que al utilizar etiquetas de propiedad, como referencia a un grano de los

padres. Si bien se muestra como un ejemplo, lo mejor es elegir bien el pag

etiquetas de espacio de nombres o de propiedad para definir sus granos, en lugar de la mezcla de estilos (a menos que sea absolutamente necesario).

Aquí está el resultado de la ejecución del HierarchicalAppContextUsage clase:

de CTX padres: La gravedad del niño


CTX: No hay tal cosa de los padres CTX:
Hijas

Como era de esperar, la song1 y Song3 habas tanto obtener una referencia a los granos en la matriz
Application Context, mientras que el song2 frijol obtiene una referencia a un grano en el niño Application Context.

La inyección de Colecciones

A menudo, los granos deben tener acceso a las colecciones de objetos en lugar de sólo los granos o los valores individuales. Por lo tanto, no debería ser una
sorpresa que la primavera le permite inyectar una colección de objetos en una de sus granos. El uso de la colección es simple: elige cualquiera < la lista>, <map>,
<set>, o < puntales> para representar una Lista, mapa, Conjunto, o propiedades instancia, y luego se pasa en los elementos individuales del mismo modo que lo haría
con cualquier otra inyección. la < puntales> etiqueta permite solamente Cuerda s que se pasa como el valor, debido a que la propiedades clase permite sólo para los
valores de las propiedades que sean Cuerda s. Cuando se utiliza < la lista>, <map>, o < set> se puede utilizar cualquier etiqueta que desee cuando se inyectan en una
propiedad, incluso otra etiqueta de colección. Esto le permite pasar de una Lista de Mapa s, una

Mapa de Conjunto s, o incluso una Lista de Mapa s de Conjunto s de Lista s! El siguiente fragmento de código se muestra una clase que puede tener los cuatro tipos de

colección inyectados en él:

com.apress.prospring5.ch3.xml paquete;

org.springframework.context.support.GenericXmlApplicationContext importación;

java.util.List importación; java.util.Map


importación; java.util.Properties de
importación; java.util.Set importación;

CollectionInjection public class {

Map <String, Object> mapa privado; apoyos de las


propiedades privadas; Conjunto privado establecido;
listado privada;

77
Capítulo 3 ■ La introducción de la COI y Di en primavera

public void (String ... args) {


GenericXmlApplicationContext ctx =
nuevo GenericXmlApplicationContext (); ctx.load ( "ruta de clase:
primavera / app-contexto-xml.xml"); ctx.refresh ();

ejemplo CollectionInjection =
(CollectionInjection) ctx.getBean ( "injectCollection"); instance.displayInfo ();

ctx.close (); }

displayInfo public void () {


System.out.println ( "contenido Mapa: \ n");
map.entrySet () corriente () forEach (e -..> System.out.println (
"Clave:" + e.getKey () + "- Valor:" + e.getValue ()));

System.out.println ( "\ nProperties contenido: \ n"); props.entrySet () corriente ()


forEach (e -..> System.out.println (
"Clave:" + e.getKey () + "- Valor:" + e.getValue ()));

System.out.println ( "contenidos \ NSET: \ n");


set.forEach (obj -> System.out.println ( "Valor:" + obj));

System.out.println ( "contenidos \ nlist: \ n"); list.forEach (obj ->


System.out.println ( "Valor:" + obj)); }

public void setlist (listado) {


This.List = lista; }

public void setset (SET SET) {


this.set = SET; }

setMap pública vacío (Map <String, Object> Mapa) {


this.map = mapa; }

SetProps public void (apoyos Bien) {


this.props = puntales; }}

Ese es un montón de código, pero lo que realmente hace muy poco. los principal() método recupera una
CollectionInjection frijol de primavera y luego llama al displayInfo () método. Este método solo da salida a los contenidos de la Mapa, Propiedades,
establezca, y Lista instancias que se inyectarán de primavera. La configuración requerida para inyectar valores para cada una de las propiedades
en el CollectionInjection clase se representa a continuación, y el archivo de configuración se denomina App-contexto-xml.xml.

78
Capítulo 3 ■ La introducción de la COI y Di en primavera

También, observe la declaración de la Map <String, Object> propiedad. Para las versiones más recientes que JDK 5, la primavera también es
compatible con la inflexible Colección declaración y llevará a cabo la conversión de la configuración XML al tipo correspondiente especificada en
consecuencia.

<Habas ...>

<Bean id = "lyricHolder"
lass = "com.apress.prospring5.ch3.xml.LyricHolder" />

<Bean id = "injectCollection"
class = "com.apress.prospring5.ch3.xml.CollectionInjection"> <property name =
"mapa">
<Mapa>

<Entry key = "someValue">


<Valor> Es un viernes, que finalmente lo hizo </ value> </ entry>

<Entry key = "someBean">


<Bean ref = "lyricHolder" /> </ entry>
</ MAP> </ property>

<Property name = "apoyos">


<Puntales>

<Prop clave = "nombre"> John </ prop> <key =


"secondName" prop> Mayer </ prop> </ apoyos> </ property>

<Property name = "set">


<Set>
<Valor> No puedo creer que tengo la oportunidad de ver su cara </ value> <bean ref
= "lyricHolder" /> </ set> </ property>

<Property name = "lista">


<Lista>
<Valor> Usted ha estado trabajando y he estado esperando </ value> <bean ref =
"lyricHolder" /> </ list> </ property> </ bean> </ beans>

En este código, se puede ver que hemos inyectado valores en los cuatro emisores expuestos en el
CollectionInjection clase. Para el mapa propiedad, hemos inyectado una Mapa instancia mediante el < mapa> etiqueta. Observe que cada entrada se especifica
utilizando un < entrada> tag, y cada uno tiene una Cuerda llave y luego un valor de entrada. Este valor de entrada puede ser cualquier valor que se puede inyectar en
una propiedad por separado; Este ejemplo muestra el uso de la
<Valor> y < ref> etiquetas para añadir un Cuerda valor y una referencia de frijol a la Mapa. los LyricHolder clase, que es del tipo de la lyricHolder
bean inyecta en el mapa en la configuración anterior, se representa aquí:

79
Capítulo 3 ■ La introducción de la COI y Di en primavera

com.apress.prospring5.ch3.xml paquete;

com.apress.prospring5.ch3.ContentHolder importación;

clase pública implementa LyricHolder ContentHolder {


Valor de la cadena privada = "" Usted sea el DJ, voy a ser el conductor";

@Override public String toString () {


volver "LyricHolder: {" + valor + "}"; }}

Para el accesorios propiedad, se utiliza el < puntales> etiqueta para crear una instancia de java.util.Properties y rellenarla usando <prop> etiquetas.
Tenga en cuenta que aunque el < prop> etiqueta está enchavetado de una manera similar a la
<Entry> etiqueta, sólo podemos especificar Cuerda valores para cada propiedad que va en la propiedades ejemplo.
También, para el < mapa> elemento hay una alternativa, la configuración más compacta usando el valor y
Valor de ref atributos, en lugar de la < valor> y < ref> elementos. los mapa declarado aquí es equivalente a la de la configuración
anterior:

<Property name = "mapa">


<Mapa>

<Entry key = "someValue" = "Es un viernes, que finalmente lo hizo" /> <clave de entrada = = /
"lyricHolder" "someBean" valor-ref> </ map> </ property>

Tanto el < la lista> y < set> etiquetas funcionan de la misma manera: se especifica cada elemento mediante el uso de cualquiera de las etiquetas de
valores individuales como < valor> y < ref> que se utilizan para inyectar un solo valor en una propiedad. En la configuración anterior, se puede ver que hemos
añadido una Cuerda valor y una referencia de frijol tanto a la
Lista y Conjunto instancias.
Aquí está la salida generada por el principal() método en la clase CollectionInjection. Como era de esperar, que se limita a enumerar los elementos
añadidos a las colecciones del archivo de configuración.

Mapa contenidos:

Clave: someValue - Valor: Es un viernes, que finalmente lo hizo


Clave: someBean - Valor: LyricHolder: { 'Usted es el DJ, voy a ser el conductor'}

Propiedades de los contenidos:

Clave: secondName - Valor: Mayer clave:


primerNombre - Valor: John

Contenido del juego:

Valor: No puedo creer que tengo la oportunidad de ver su cara Valor: LyricHolder: {
'Usted es el DJ, voy a ser el conductor'}

contenido de la lista:

Valor: Usted ha estado trabajando y he estado esperando Valor: LyricHolder: {


'Usted es el DJ, voy a ser el conductor'}

80
Capítulo 3 ■ La introducción de la COI y Di en primavera

Recuerde que con el < la lista>, <map>, y < set> elementos, se puede emplear cualquiera de las etiquetas que se utilizan para establecer el valor de las
propiedades no cobro para especificar el valor de una de las entradas de la colección. Este es un concepto muy poderoso porque usted no está limitado sólo para
la inyección de colecciones de valores primitivos; también se puede inyectar colecciones de granos u otras colecciones.

El uso de esta funcionalidad, es mucho más fácil de modularizar su solicitud y proporcionar diferentes implementaciones, userselectable de piezas clave
de la lógica de la aplicación. Considere un sistema que permite al personal de las empresas para crear, corregir, y ordenar su negocio de papelería
personalizada en línea. En este sistema, la obra acabada para cada orden se envía a la impresora adecuada cuando está listo para la producción. La única
complicación es que algunas impresoras quieren recibir la obra a través de correo electrónico, algunos a través de FTP, y otras personas que utilizan Secure
Copy Protocol (SCP). Utilizando la inyección de la colección de primavera, se puede crear una interfaz estándar para esta funcionalidad, como se muestra en el
siguiente fragmento de código:

com.apress.prospring5.ch3 paquete;

ArtworkSender interfaz pública {


anular sendArtwork (String artworkPath, receptor destinatario); Cadena
getFriendlyName (); Cadena getShortName (); }

En el ejemplo anterior, el Recipiente clase es una clase vacía. Desde esta interfaz, puede crear múltiples implementaciones, cada uno de los cuales
es capaz de describir en sí a un ser humano, como el que se muestra a continuación:

com.apress.prospring5.ch3 paquete;

FtpArtworkSender clase pública


implementa ArtworkSender {

@Anular
sendArtwork pública vacío (String artworkPath, receptor destinatario) {
// ftp lógica aquí ...}

@Anular
Cadena getFriendlyName pública () {
volver "File Transfer Protocol"; }

@Anular
Cadena getShortName pública () {
volver "ftp"; }}

Imagine que luego desarrolla una ArtworkManager clase que es compatible con todas las implementaciones disponibles de la Obra-remitente interfaz.
Con las implementaciones en su lugar, sólo tiene que pasar una Lista para usted
ArtworkManager clase, y usted está en su camino. Utilizando la getFriendlyName () método, se puede mostrar una lista de opciones de entrega
para el administrador del sistema para elegir cuando se está configurando cada plantilla de papelería. Además, su aplicación puede permanecer
totalmente desacoplado de las implementaciones individuales si sólo código para el ArtworkSender interfaz. Vamos a salir de la aplicación de la ArtworkManag
clase como un ejercicio para usted.

81
Capítulo 3 ■ La introducción de la COI y Di en primavera

Además de la configuración de XML, puede utilizar las anotaciones para inyección colección. Sin embargo, también le gustaría externalizar los
valores de las colecciones en el archivo de configuración para un fácil mantenimiento. El siguiente fragmento es la configuración de cuatro granos de
resorte diferentes que imitan las mismas propiedades de la colección de la muestra anterior (archivo de configuración app-contexto-annotation.xml):

<? Xml version = "1.0" encoding = "UTF-8"?>


<habas xmlns = "http://www.springframework.org/schema/beans"
xmlns: xsi = "http://www.w3.org/2001/XMLSchema-instance" xmlns: contexto =
"http://www.springframework.org/schema/context" xmlns: util = "http: // www
.springframework.org / esquema / util "xsi: schemaLocation ="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd ">

<Context: componente-scan
base paquete = "com.apress.prospring5.ch3.annotated" />

<Util: mapa id = "mapa" mapa de clase = "java.util.HashMap">


<Clave de entrada = valor "someValue" = "Es un viernes, que finalmente lo hizo" /> <entry key =
"someBean" valor-ref = "lyricHolder" /> </ util: mapa>

<Util: Propiedades Id = "puntales">


<Key = "Nombre" prop> John </ prop> <prop key =
"secondName"> Mayer </ prop> </ Útil: properties>

<Util: Conjunto id = "set" clase ubicada = "java.util.HashSet">


<Valor> No puedo creer que tengo la oportunidad de ver su cara </ value> <ref frijol
= "lyricHolder" /> </ util: set>

<Util: Lista id = "lista" lista de clase = "java.util.ArrayList">


<Valor> Usted ha estado trabajando y he estado esperando </ value> <bean ref =
"lyricHolder" /> </ util: lista> </ beans>

También vamos a desarrollar una versión de la anotación LyricHolder clase. El contenido de clase se representa aquí:

com.apress.prospring5.ch3.annotated paquete;

com.apress.prospring5.ch3.ContentHolder importación;
org.springframework.stereotype.Service importación;

@Service ( "lyricHolder")
clase pública implementa LyricHolder ContentHolder {

82
Capítulo 3 ■ La introducción de la COI y Di en primavera

Valor de la cadena privada = "" Usted sea el DJ, voy a ser el conductor";

@Override public String toString () {


volver "LyricHolder: {" + valor + "}"; }}

En la configuración representada anteriormente, hacemos uso de la util espacio de nombres proporcionada por el resorte de declarar sus granos para
almacenar propiedades de la colección: la util espacio de nombres. Se simplifica en gran medida la configuración, en comparación con las versiones anteriores de
la primavera. En la clase se utiliza para probar la configuración, inyectamos las habas y uso previo de la JSR-250 @ Recurso anotación con el nombre especificado
como un argumento para identificar correctamente los granos. los displayInfo () método es el mismo que antes, así que ya no se muestra aquí.

@Service ( "injectCollection") public class


{CollectionInjection
@Resource (name = "mapa")
Map <String, Object> mapa privado;

@Resource (name = "apoyos") Propiedades


de los apoyos privados;

@Resource (name = "set") Conjunto

privada establecida;

@Resource (name = "lista")


listado privada;

public void (String ... args) {


GenericXmlApplicationContext ctx =
nuevo GenericXmlApplicationContext ();
ctx.load ( "ruta de clase: primavera / app-contexto-annotation.xml"); ctx.refresh ();

ejemplo CollectionInjection = (CollectionInjection)


ctx.getBean ( "injectCollection");
instance.displayInfo ();

ctx.close (); }

...
}

Ejecutar el programa de pruebas, y obtendrá el mismo resultado que la muestra utilizando la configuración de XML.

83
Capítulo 3 ■ La introducción de la COI y Di en primavera

Usted puede preguntarse por qué la anotación @ Recurso se utiliza en lugar de @ Autowired. Es debido a que la

@Autowired anotación se define semánticamente de una manera que siempre trata a arrays, colecciones y mapas como conjuntos de granos

correspondientes, con el tipo de frijol diana derivado del tipo de valor de la colección declarado. Así, por ejemplo, si una clase tiene un atributo de

tipo Lista <ContentHolder> y tiene la @ Autowired anotación definida, Primavera trate de inyectar todos los granos de tipo ContentHolder dentro de la

corriente Application Context en ese atributo (en lugar de la < util: lista> declarado en el archivo de configuración), lo que resultará en cualquiera de las

dependencias inesperados que se inyecta o primavera lanzar una excepción si no bean de tipo ContentHolder

Fue definido. Por lo tanto, para la inyección de tipo de colección, tenemos que instruir explícitamente primavera para llevar a cabo la inyección

especificando el nombre del bean, que la @ Recurso anotación apoya.

Una combinación de @ Autowired y @ Índice Se puede utilizar para cumplir con el mismo propósito, pero siempre es preferible utilizar una

anotación y no dos. En el siguiente fragmento de código, se puede ver la configuración equivalente a inyectar una colección utilizando su nombre de frijol

mediante el uso de @ Autowired y @ Índice.

com.apress.prospring5.ch3.annotated paquete;

org.springframework.beans.factory.annotation.Autowired importación;
org.springframework.beans.factory.annotation.Qualifier importación; @Service (
"injectCollection") public class {CollectionInjection

@Autowired

@Qualifier ( "mapa")

Map <String, Object> mapa privado;


...}

Utilizando el Método de Inyección

Además constructor y la inyección de setter, otra característica DI menos frecuentemente utilizado que Spring proporciona es
Inyección método. Método capacidades de inyección de primavera vienen en dos formas vagamente relacionados, Método de búsqueda de inyección y
de reemplazo Método. Lookup Método Inyección proporciona otro mecanismo por el que un grano puede obtener una de sus dependencias. Método de
sustitución le permite reemplazar la aplicación de cualquier método en un grano de forma arbitraria, sin tener que cambiar el código fuente original. Para
proporcionar estas dos características, Spring utiliza las capacidades de mejora de bytecode dinámicos de CGLIB. 3

3 cglib es un potente y de alto rendimiento, y la biblioteca de generación de código de alta calidad. Además, puede extenderse clases Java e implementar las interfaces en tiempo de

ejecución. Es de código abierto, y se puede encontrar en el repositorio oficial https://github.com/cglib .

84
Capítulo 3 ■ La introducción de la COI y Di en primavera

Método de Inyección de búsqueda

Método de Inyección de búsqueda se añadió a la primavera en la versión 1.1 para superar los problemas encontrados cuando un grano de frijol depende de
otro con un ciclo de vida diferente, específicamente, cuando un conjunto unitario depende de un más de un elemento. En esta situación, tanto de la moda y el
constructor resultado de la inyección en el singleton mantener una única instancia de lo que debería ser un grano más de un elemento. En algunos casos,
tendrá que tener el grano Singleton obtener una nueva instancia de la cada vez más de un elemento que requiere el grano en cuestión.

Consideremos un escenario en el que una LockOpener clase proporciona el servicio de abrir cualquier vestuario. los
LockOpener clase se basa en una KeyHelper clase para abrir el armario, que se inyecta en LockOpener.
Sin embargo, el diseño de la KeyHelper clase implica algunos estados internos que lo hacen no aptos para su reutilización. Cada vez que el openLock
() método se llama, un nuevo KeyHelper Se requiere instancia. En este caso, LockOpener
será un producto único. Sin embargo, si inyectamos el KeyHelper clase utilizando el mecanismo normal, la misma instancia de la KeyHelper será
reutilizado clase (que se crea una instancia cuando la primavera realizó la inyección de la primera vez). Para asegurarse de que una nueva
instancia de la KeyHelper ejemplo se pasa a la openLock ()
método cada vez que se invoca, tenemos que utilizar la búsqueda Método de Inyección.
Por lo general, se puede lograr esto haciendo que el grano de implementar el singleton ApplicationContextAware
interfaz (hablamos de esta interfaz en el siguiente capítulo). Luego, utilizando la Application Context ejemplo, el grano de Singleton puede buscar una nueva
instancia de la dependencia más de un elemento cada vez que lo necesita. Método de Inyección de búsqueda permite que el grano de Singleton a declarar
que requiere una dependencia más de un elemento y que recibirá una nueva instancia del bean de más de un elemento cada vez que tiene que interactuar
con él, sin necesidad de aplicar ninguna interfaz de primavera-específica.

trabajos de inyección de búsqueda de métodos por tener su Singleton declarar un método, el método de búsqueda, que devuelve una instancia del
bean de más de un elemento. Al obtener una referencia al producto único en su aplicación, en realidad se está recibiendo una referencia a una subclase
creado de forma dinámica en la que la primavera ha implementado el método de búsqueda. Una aplicación típica implica la definición del método de
búsqueda, y por lo tanto la clase de bean, como abstracta. Esto evita cualquier error extraños se filtren en cuando se olvida de configurar la inyección
Método y que están trabajando directamente en contra de la clase de bean con la implementación del método vacía en lugar de la subclase
Primavera-mejorada. Este tema es bastante complejo y se muestra mejor con el ejemplo.

En este ejemplo, creamos un grano más de un elemento y dos granos simples que tanto implementar la misma interfaz. Uno de los singletons
obtiene una instancia de la haba de más de un elemento mediante el uso de inyección “tradicional” setter; el otro utiliza el método de inyección. El
siguiente ejemplo de código muestra el Cantante clase, que en este ejemplo es el tipo de la haba de más de un elemento:

com.apress.prospring5.ch3 paquete;

El cantante public class {


Cadena lírica privada = "He jugado un juego rápido de ajedrez con la sal
y pimienta agitador ";

public void cantar () {


// comentado porque contamina la salida
//System.out.println(lyric); }}

Esta clase es decididamente poco atractiva, pero sirve a los propósitos de este ejemplo a la perfección. A continuación, se puede ver la DemoBean interfaz,
que se implementa por tanto de las clases de frijol únicos.

com.apress.prospring5.ch3 paquete; DemoBean


interfaz pública {
Cantante getMySinger (); void
doSomething (); }

85
Capítulo 3 ■ La introducción de la COI y Di en primavera

Este bean tiene dos métodos: getMySinger () y hacer algo(). La aplicación de ejemplo utiliza el
getMySinger () método para obtener una referencia a la Cantante instancia y, en el caso de la haba de búsqueda método, para realizar las operaciones de
búsqueda método real. los hacer algo() método es un método sencillo que depende de la
Cantante clase haga su procesamiento. El siguiente fragmento de código muestra la StandardLookupDemoBean clase, que utiliza una inyección de setter
para obtener una instancia de la Cantante clase:

com.apress.prospring5.ch3 paquete;

StandardLookupDemoBean clase pública


implementa DemoBean {

mySinger cantante privado;

setMySinger pública vacío (Singer mySinger) {


this.mySinger = mySinger; }

@Anular
El cantante pública getMySinger () {
volver this.mySinger; }

@Anular
doSomething public void () {
mySinger.sing (); }}

todo este código debería ser familiar, pero notar que la hacer algo() método utiliza la instancia almacenada de
Cantante para completar su tratamiento. En el siguiente fragmento de código, se puede ver la AbstractLookupDemoBean
clase, que utiliza el método de inyección para obtener una instancia de la Cantante clase.

com.apress.prospring5.ch3 paquete;

AbstractLookupDemoBean clase abstracta pública


implementa DemoBean {
El cantante abstracta pública getMySinger ();

@Anular
doSomething public void () {
getMySinger () cantar ().; }}

Observe que el getMySinger () método se declara como abstracto y que este método es llamado por el
hacer algo() método para obtener una Cantante ejemplo. La configuración XML de Spring para este ejemplo está contenida en un archivo
llamado App-contexto-xml.xml y se muestra aquí:

<Habas ...>
<Bean id = clase "cantante" = "com.apress.prospring5.ch3.Singer"
scope = "prototipo" />

86
Capítulo 3 ■ La introducción de la COI y Di en primavera

<Bean id = "abstractLookupBean"
class => <lookup-método "com.apress.prospring5.ch3.AbstractLookupDemoBean"
name = "getMySinger" grano = "cantante" /> </ bean>

<Bean id = "standardLookupBean"
class = "com.apress.prospring5.ch3.StandardLookupDemoBean"> <property name =
"mySinger" ref = "cantante" /> </ bean> </ beans>

La configuración para el cantante y standardLookupBean granos deben resultar familiar a usted por ahora. por abstracto-LookupBean, es necesario
configurar el método de búsqueda mediante el uso de la etiqueta < lookup-method> etiqueta. los
nombre atributo de la < lookup-method> Primavera etiqueta le dice el nombre del método en el grano que debe pasar por encima. Este método no debe
aceptar ningún argumento, y el tipo de retorno debe ser el del frijol que desea devolver a partir del método. En este caso, el método debe devolver
una clase de tipo Cantante, o de sus subclases. El atributo de frijol de primavera, que dice frijol el método de búsqueda debe devolver. El siguiente
fragmento de código se muestra la pieza final del código para este ejemplo, que es la clase que contiene la principal() método utiliza para ejecutar el
ejemplo:

com.apress.prospring5.ch3 paquete;

org.springframework.context.support.GenericXmlApplicationContext importación;
org.springframework.util.StopWatch importación;

LookupDemo public class {


public void (String ... args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext (); ctx.load ( "ruta de
clase: primavera / app-contexto-xml.xml"); ctx.refresh ();

DemoBean abstractBean = ctx.getBean ( "abstractLookupBean",


DemoBean.class);
DemoBean standardBean = ctx.getBean ( "standardLookupBean",
DemoBean.class);

displayInfo ( "abstractLookupBean", abstractBean); displayInfo (


"standardLookupBean", standardBean);

ctx.close (); }

public static void displayInfo (String beanName, frijol DemoBean) {


Cantante singer1 = bean.getMySinger (); Cantante
Singer2 = bean.getMySinger ();

System.out.println ( "" + + "beanName: Instancias Singer lo mismo"?


+ (Singer1 == Singer2));

87
Capítulo 3 ■ La introducción de la COI y Di en primavera

Cronómetro Cronómetro = new StopWatch ();


stopWatch.start ( "lookupDemo"); for (int x = 0; x <100
000; x ++) {
Cantante = bean.getMySinger (); singer.sing (); }

stopWatch.stop ();

System.out.println ( "100000 consigue tomaron"


+ stopWatch.getTotalTimeMillis () + "ms");
}}

En este código, se puede ver que el abstractLookupBean y el standardLookupBean desde el


GenericXmlApplicationContext se recuperan y cada referencia se pasa a la displayInfo () método. La instanciación de la clase abstracta sólo
se admite cuando se utiliza Lookup Método de inyección, en el que la primavera utilizará CGLIB para generar una subclase de la AbstractLookupDemoBean
clase que reemplaza el método dinámicamente. La primera parte de la displayInfo () método crea dos variables locales de Cantante escribir y
les asigna a cada uno un valor llamando getMySinger () en el grano que se le pasa. El uso de estas dos variables, se escribe un mensaje en
la consola que indica si las dos referencias apuntan al mismo objeto.

Para el abstractLookupBean haba, una nueva instancia de Cantante debe ser recuperada para cada llamada a
getMySinger (), por lo que las referencias no deben ser los mismos.
por standardLookupBean, una única instancia de Cantante se pasa al frijol por inyección organismo, y este caso se almacena y se devuelve
para cada llamada a getMySinger (), por lo que las dos referencias deben ser los mismos.

la Cronógrafo clase utilizada en el ejemplo anterior es una clase de utilidad disponible con la primavera. Encontrarás

Cronógrafo muy útil cuando se necesita para llevar a cabo pruebas de rendimiento simples y cuando se está probando sus aplicaciones.

La parte final de la displayInfo () método se ejecuta una prueba de funcionamiento sencillo para ver cuál es más rápido frijol. Claramente, standardLookupBean
debe ser más rápido porque devuelve la misma instancia cada vez, pero es interesante ver la diferencia. Ahora podemos ejecutar el LookupDemo clase
para la prueba. Aquí está la salida que recibimos de este ejemplo:

[AbstractLookupBean]: Instancias Singer lo mismo? 100000 falsa consigue


tomaron 431 ms

[StandardLookupBean]: Instancias Singer lo mismo? 100000 cierto consigue


tomó 1 ms

Como se puede ver, el Cantante Las instancias son, como se esperaba, el mismo cuando usamos standardLookupBean y diferente cuando
usamos abstractLookupBean. Hay una diferencia notable en el rendimiento cuando se utiliza
standardLookupBean, pero eso es de esperar.
Por supuesto, hay una manera equivalente a configurar los granos presentados anteriormente utilizando anotaciones. los
cantante bean debe tener una anotación adicional para especificar el prototipo alcance.

com.apress.prospring5.ch3.annotated paquete;

88
Capítulo 3 ■ La introducción de la COI y Di en primavera

org.springframework.context.annotation.Scope importación;
org.springframework.stereotype.Component importación;

@Component ( "cantante)
@Scope (" prototipo ") Singer
public class {
Cadena lírica privada = "He jugado un juego rápido de ajedrez
con la sal y la pimienta agitador ";

public void cantar () {


// comentado para evitar la contaminación de la consola
//System.out.println(lyric); }}

los AbstractLookupDemoBean de clases ya no es una clase abstracta, y el método getMySinger () tiene un cuerpo vacío y está
anotado con @ Buscar que recibe como argumento el nombre de la Cantante frijol. El cuerpo del método será anulado, en la subclase
generado dinámicamente.

com.apress.prospring5.ch3.annotated paquete;

org.springframework.beans.factory.annotation.Lookup importación;
org.springframework.stereotype.Component importación;

@Component ( "abstractLookupBean")
clase pública implementa AbstractLookupDemoBean DemoBean {
@Lookup ( "cantante")
El cantante pública getMySinger () {
nula regresar; // anulado dinámicamente}

@Anular
doSomething public void () {
getMySinger () cantar ().; }}

los StandardLookupDemoBean única clase debe ser anotado con @ Componente, y setMySinger debe ser anotado con @ Autowired
y @ Índice para inyectar el cantante frijol.

com.apress.prospring5.ch3.annotated paquete;

org.springframework.beans.factory.annotation.Autowired importación;
org.springframework.beans.factory.annotation.Qualifier importación;
org.springframework.stereotype.Component importación;

@Component ( "standardLookupBean")
clase pública implementa StandardLookupDemoBean DemoBean {

mySinger cantante privado;

89
Capítulo 3 ■ La introducción de la COI y Di en primavera

@Autowired
@Qualifier ( "cantante")
setMySinger pública vacío (Singer mySinger) {
this.mySinger = mySinger; }

@Anular
El cantante pública getMySinger () {
volver this.mySinger; }

@Anular
doSomething public void () {
mySinger.sing (); }}

El archivo de configuración, el nombre App-contexto-annotated.xml, sólo se debe activar el análisis de componentes para el paquete que
contiene las clases anotadas.

<Habas ...>

<Context: componente-scan
base paquete = "com.apress.prospring5.ch3.annotated" />
</ Beans>

La clase se utiliza para ejecutar el código es idéntico a la clase LookupDemo; la única diferencia es el archivo XML utilizado como un
argumento para crear el GenericXmlApplicationContext objeto.
Si queremos deshacernos de archivos XML totalmente, esto se puede hacer usando una clase de configuración para activar el análisis del
componente en el com.apress.prospring5.ch3.annotated paquete. Y esta clase puede ser declarado justo donde lo necesita, es decir, en este caso
dentro de la clase que se ejecuta para probar los granos, como se muestra aquí:

com.apress.prospring5.ch3.config paquete;

com.apress.prospring5.ch3.annotated.DemoBean importación;
com.apress.prospring5.ch3.annotated.Singer importación;
org.springframework.context.annotation.AnnotationConfigApplicationContext importación;
org.springframework.context.annotation.ComponentScan importación;
org.springframework.context.annotation.Configuration importación;
org.springframework.context.support.GenericApplicationContext importación; org.springframework.util.StopWatch
importación;

java.util.Arrays de importación;

LookupConfigDemo public class {

@Configuración
@ComponentScan (basePackages = { "com.apress.prospring5.ch3.annotated"}) LookupConfig
clase public static {}

90
Capítulo 3 ■ La introducción de la COI y Di en primavera

public void (String ... args) {


GenericApplicationContext ctx =
nuevo AnnotationConfigApplicationContext (LookupConfig.class);

DemoBean abstractBean = ctx.getBean ( "abstractLookupBean",


DemoBean.class);
DemoBean standardBean = ctx.getBean ( "standardLookupBean",
DemoBean.class);

displayInfo ( "abstractLookupBean", abstractBean); displayInfo (


"standardLookupBean", standardBean);

ctx.close (); }

public static void displayInfo (String beanName, frijol DemoBean) {


// misma aplicación como antes
...
}}

configuraciones alternativas utilizando anotaciones y configuración Java se tratan en más detalle en el capítulo 4 .

Consideraciones para la búsqueda Método de Inyección

Método de Inyección de búsqueda es para uso cuando se quiere trabajar con dos granos de diferentes ciclos de vida. Evitar la tentación de utilizar la
búsqueda Método de inyección cuando los granos comparten el mismo ciclo de vida, sobre todo si son únicos. La salida de ejecutar el ejemplo anterior
muestra una diferencia notable en el rendimiento entre usando el Procedimiento de inyección para obtener nuevas instancias de una dependencia y el uso
de DI estándar para obtener una sola instancia de una dependencia. Además, asegúrese de que no utilice el método de búsqueda de inyección sin
necesidad, incluso cuando se tiene granos de diferentes ciclos de vida.

Considere una situación en la que tiene tres hijos únicos que comparten una dependencia en común. Desea que cada producto único que
tiene su propia instancia de la dependencia, por lo que se crea la dependencia como más de un elemento, pero usted es feliz con cada producto
único con la misma instancia del colaborador lo largo de su vida. En este caso, la inyección de setter es la solución ideal; Método de Inyección de
búsqueda sólo añade una sobrecarga innecesaria.

Cuando se utiliza el método de búsqueda de inyección, hay algunas pautas de diseño que usted debe tener en cuenta en la construcción de sus
clases. En los ejemplos anteriores, declaramos el método de búsqueda en una interfaz. La única razón por la que hicimos esto fue que no tuvimos que
duplicar la displayInfo () método de dos veces por dos tipos de frijol diferentes. Como se mencionó anteriormente, en general, no es necesario para
contaminar una interfaz de negocios con las definiciones innecesarias que se utilizan únicamente con fines COI. Otro punto es que a pesar de que no
tiene que hacer que su método de búsqueda abstracta, haciendo así que le impide olvidar para configurar el método de búsqueda y luego usando una
aplicación en blanco por accidente. Por supuesto, esto sólo funciona con configuración XML. configuración basada en anotación obliga a una
aplicación vacío del método; de lo contrario, no se creará el bean.

91
Capítulo 3 ■ La introducción de la COI y Di en primavera

reemplazo método
Aunque la documentación de Primavera clasifica reemplazo método como una forma de inyección, es diferente de lo que hemos visto hasta ahora. Hasta
ahora, hemos utilizado la inyección puramente para suministrar los granos con sus colaboradores. Utilizando el método de sustitución, se puede sustituir la
aplicación de cualquier método de cualquier habas arbitrariamente sin tener que cambiar la fuente del grano que se está modificando. Por ejemplo, usted
tiene una biblioteca de terceros que se utiliza en la aplicación de la primavera, y es necesario cambiar la lógica de un determinado método. Sin embargo, no
son capaces de cambiar el código fuente, ya que fue proporcionado por un tercero, por lo que una solución es utilizar el método de reemplazo simplemente
reemplazar la lógica para ese método con su propia aplicación.

Internamente, a lograr esto mediante la creación de una subclase de la clase de bean de forma dinámica. Se utiliza CGLIB y redirigir las
llamadas al método que desea reemplazar a otro bean que implementa el MethodReplacer
interfaz. En el siguiente ejemplo de código, se puede ver un grano simple que declara dos sobrecargas del
FormatMessage () método:

com.apress.prospring5.ch3 paquete;

ReplacementTarget public class {


Cadena FORMATMESSAGE pública (String msg) {
volver "<h1>" + MSG + "</ h1>"; }

Cadena FORMATMESSAGE pública (msg Object) {


volver "<h1>" + MSG + "</ h1>"; }}

Puede reemplazar cualquiera de los métodos en el ReplacementTarget clase utilizando la funcionalidad de reemplazo método de la
primavera. En este ejemplo, le mostramos cómo sustituir la FormatMessage (String)
método, y también comparar el rendimiento del método reemplazado a la de la original.
Para sustituir un método, primero tiene que crear una aplicación de la MethodReplacer interfaz; esto se muestra en el siguiente ejemplo
de código:

com.apress.prospring5.ch3 paquete;

org.springframework.beans.factory.support.MethodReplacer importación;

java.lang.reflect.Method importación;

FormatMessageReplacer clase pública


implementa MethodReplacer {

@Anular
reimplementar pública de objetos (arg0 objeto, método Método, objeto ... args)
lanza Throwable {if
(isFormatMessageMethod (método)) {
Cadena msg = (String) args0; volver
"<h2>" + msg + "</ h2>"; } Else {

arrojar nueva IllegalArgumentException ( "No se puede volver a implementar el método"


+ method.getName ()); }}

92
Capítulo 3 ■ La introducción de la COI y Di en primavera

isFormatMessageMethod boolean privado (método Método) {


si (method.getParameterTypes (). longitud! = 1) {
falso retorno; }

if (! (.equals "FORMATMESSAGE" (method.getName ()))) {


falso retorno; }

si (method.getReturnType ()! = String.class) {


falso retorno; }

(si method.getParameterTypes () [0]! = String.class) {


falso retorno; }

return true; }}

los MethodReplacer interfaz tiene un único método, reimplementar (), que se debe aplicar. Tres argumentos se pasan
a reimplementar (): el grano en la que se invoca el método original, una
Método instancia que representa el método que se está anulado, y la matriz de argumentos pasados ​al método. los reimplementar () método
debe devolver el resultado de la lógica reimplantado, y, obviamente, el tipo del valor de retorno debe ser compatible con el tipo de
retorno del método que está reemplazando. En el ejemplo de código anterior, FormatMessageReplacer comprueba primero para ver si el
método que se está anulado es la FormatMessage (String) método; si es así, ejecuta la lógica de reposición (en este caso, que rodea el
mensaje con < h2> y </ h2>) y devuelve el mensaje formateado a la persona que llama. No es necesario comprobar si el mensaje es
correcto, pero esto puede ser útil si está utilizando unos pocos MethodReplacer s con argumentos similares. El uso de un cheque ayuda
a evitar una situación en la que un diferente

MethodReplacer con argumentos compatibles y tipos de retorno se utiliza de forma accidental.


En la muestra de configuración de la lista siguiente, se puede ver una Application Context instancia que define dos granos de tipo ReplacementTarget;
uno tiene la FormatMessage (String) método reemplazado, y el otro no lo hace (el archivo se llama app-contexto-xml.xml):

<Habas ...>

<Bean id = "methodReplacer"
class = "com.apress.prospring5.ch3.FormatMessageReplacer" />

<Bean id = "replacementTarget"
class = "com.apress.prospring5.ch3.ReplacementTarget"> <nombre-método reemplazado =
sustituto "FormatMessage" = "methodReplacer">
<Arg-type> cadena </ arg-type> </ método
reemplazado> </ bean>

<Bean id = "standardTarget"
class = "com.apress.prospring5.ch3.ReplacementTarget" /> </ beans>

93
Capítulo 3 ■ La introducción de la COI y Di en primavera

Como se puede ver, el MethodReplacer aplicación se declara como un grano en el Application Context.
A continuación, utiliza el < sustituido-method> etiqueta para sustituir el FormatMessage (String) método de
replacementTargetBean. El atributo nombre de la < sustituido-method> etiqueta especifica el nombre del método para sustituir, y el atributo
sustituto se utiliza para especificar el nombre de la MethodReplacer bean que queremos sustituir la implementación del método. En los casos
en que hay métodos tales como en el sobrecargado
ReplacementTarget clase, se puede utilizar el < arg-type> etiqueta para especificar la firma del método de igualar. los
<Arg-type> tag apoya coincidencia de patrones, por lo Cuerda está adaptada a java.lang.String y también para Java. lang.StringBuffer.

El siguiente fragmento de código muestra una aplicación de demostración simple que recupera tanto el standardTarget
y reemplazo de destino habas de Application Context, ejecuta su FormatMessage (String)
métodos y, a continuación, se ejecuta una prueba de funcionamiento sencillo para ver cuál es más rápido.

com.apress.prospring5.ch3 paquete;

org.springframework.context.support.GenericXmlApplicationContext importación;
org.springframework.util.StopWatch importación;

MethodReplacementDemo public class {


public void (String ... args) {
GenericXmlApplicationContext ctx =
nuevo GenericXmlApplicationContext (); ctx.load ( "ruta de clase:
primavera / app-contexto-xml.xml"); ctx.refresh ();

ReplacementTarget replacementTarget = (ReplacementTarget) ctx


. getBean ( "replacementTarget");
ReplacementTarget standardTarget = (ReplacementTarget) ctx
. getBean ( "standardTarget");

displayInfo (replacementTarget); displayInfo


(standardTarget);

ctx.close (); }

displayInfo (objetivo ReplacementTarget) {static void privada


System.out.println (target.formatMessage ( "Gracias por jugar, vuelve a intentarlo!"));

Cronómetro Cronómetro = new StopWatch ();


stopWatch.start ( "perftest");

for (int x = 0; x <1.000.000; x ++) {


Cadena cabo target.formatMessage = ( "Sin filtro en mi cabeza"); // comentado
que no contaminan la consola //System.out.println(out); }

stopWatch.stop ();

System.out.println ( "1000000 invocaciones llevaron:"


+ stopWatch.getTotalTimeMillis () + "ms");
}}

94
Capítulo 3 ■ La introducción de la COI y Di en primavera

Debe estar familiarizado con este código por ahora, así que no voy a entrar en detalle. En nuestra máquina, de ejecutar este ejemplo se obtiene el
siguiente resultado:

<H2> Gracias por jugar, inténtelo de nuevo </ h2> 1000000


invocaciones tomaron: 188 ms

! <H1> Gracias por jugar, inténtelo de nuevo </ h1> 1000000


invocaciones tomaron: 24 ms

Como era de esperar, la salida de la replacementTarget frijol refleja la aplicación que el reemplazado Método-Sustituto proporciona. Curiosamente,
sin embargo, el método dinámicamente sustituido es muchas veces más lento que el método estáticamente definido. Extracción del cheque por un método
válido en MethodReplacer hecho una diferencia insignificante a través de una serie de ejecuciones, por lo que podemos concluir que la mayor parte de los
gastos generales es de la subclase CGLIB.

Cuando el uso del método de reemplazo

reemplazo método puede resultar muy útil en una variedad de circunstancias, especialmente cuando se desea anular solamente un método particular para
un solo grano en lugar de todos los granos del mismo tipo. Dicho esto, seguimos prefiriendo utilizar los mecanismos estándar de Java para sobrescribir los
métodos en lugar de en función de la mejora de tiempo de ejecución de código de bytes.

Si se va a utilizar el reemplazo método como parte de su solicitud, le recomendamos que utilice uno Método-Sustituto por
método o grupo de métodos sobrecargados. Evitar la tentación de utilizar un único
MethodReplacer para las porciones de los métodos no relacionadas; esto da lugar a las comparaciones de cadenas innecesarios adicionales, mientras que
su código funciona qué método debe reimplementar. Hemos encontrado que la realización de controles simples para asegurarse de que MethodReplacer está
trabajando con el método correcto es útil y no agrega demasiado trabajo a su código. Si está realmente preocupado por el rendimiento, simplemente puede
añadir una propiedad booleana a su MethodReplacer, que le permite girar el cheque y se apaga mediante la inyección de dependencia.

Comprensión de nombres de frijol


Resorte soporta una estructura bastante compleja frijol de denominación que le permite la flexibilidad para manejar muchas situaciones.
Cada grano debe tener al menos un nombre que es único dentro de la que contiene
Application Context. La primavera sigue un proceso de solución simple para determinar qué nombre se utiliza para el bean. Si se le da la < bean> una etiqueta carné

de identidad atributo, el valor de ese atributo se utiliza como el nombre. Si no carné de identidad

atributo se especifica, Primavera busca una nombre atributo, y si uno está definido, se utiliza el primer nombre definido en el nombre atributo.
(Decimos el primer nombre, ya que es posible definir varios nombres dentro de la nombre
atributo; Esto se explica en más detalle en breve.) Si ni el carné de identidad ni el nombre atributo se especifica, Primavera utiliza nombre de la clase del
bean como el nombre, siempre, por supuesto, que ningún otro frijol está utilizando el mismo nombre de la clase. Si se declaran múltiples granos del
mismo tipo sin un ID o nombre, la primavera va a lanzar una excepción (de tipo org.springframework.beans.factory.NoSuchBeanDefinitionException) en la
inyección durante
Application Context inicialización. La siguiente configuración de ejemplo de configuración representa los tres esquemas de nombramiento ( app-contexto-01.xml):

<Habas ...>
<Bean id = clase "cadena1" = "java.lang.String" /> <bean name =
clase "string2" = "java.lang.String" /> <clase bean =
"java.lang.String" /> < / beans>

95
Capítulo 3 ■ La introducción de la COI y Di en primavera

Cada uno de estos enfoques es igualmente válido desde un punto de vista técnico, pero que es la mejor opción para su aplicación? Para empezar,
evitar el uso de la denominación automática por el comportamiento de la clase. Esto no le permite mucha flexibilidad para definir múltiples granos del
mismo tipo, y es mucho mejor para definir sus propios nombres. De esta manera, si la primavera cambia el comportamiento predeterminado en el futuro, su
aplicación sigue trabajando. Si desea ver cómo la primavera es nombrar los granos, utilizando la configuración anterior, ejecute el siguiente ejemplo:

com.apress.prospring5.ch3.xml paquete;

org.springframework.context.support.GenericXmlApplicationContext importación;

public class {BeanNamingTest


public void (String ... args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext (); ctx.load ( "ruta de
clase: primavera / app-contexto-01.xml"); ctx.refresh ();

Map <String, String> habas = ctx.getBeansOfType (String.class);

beans.entrySet () corriente () forEach (b -> System.out.println (b.getKey ()))..;

ctx.close (); }}

ctx.getBeansOfType (String.class) se utiliza para obtener un mapa con todos los granos de tipo Cuerda y sus documentos de identidad que
existen dentro de Application Context. Las llaves del mapa son los ID de frijol que se imprimen con la expresión lambda en el código anterior. Con
la configuración mencionada, esto es la salida:

cadena1
cadena2
java.lang.String # 0

La última línea en la muestra de salida anterior es el ID que la primavera dio al bean de tipo Cuerda que no fue nombrado
explícitamente en la configuración. Si la configuración se modifica para añadir otro Cuerda
frijol sin nombre, que se vería así:

<Habas ...>
<Bean id = clase "cadena1" = "java.lang.String" /> <bean name =
clase "string2" = "java.lang.String" /> <clase bean =
"java.lang.String" /> < frijol class = "java.lang.String" /> </ beans>

La salida cambiaría a lo siguiente:

cadena1
cadena2
java.lang.String # 0
java.lang.String # 1

96
Capítulo 3 ■ La introducción de la COI y Di en primavera

Con anterioridad a la primavera 3.1, el carné de identidad atributo es la misma que la identidad XML (es decir, xsd: ID), lo que sitúa una restricción en los caracteres

que puede utilizar. A partir de la primavera 3,1, utiliza Spring xsd: string Para el carné de identidad atribuir, por lo que la restricción anterior sobre los caracteres que se

pueden utilizar se ha ido. Sin embargo, la primavera seguirá garantizando que la carné de identidad es único en todo el Application Context. Como práctica general, usted

debe dar su grano de un nombre mediante el uso de la carné de identidad atribuir y luego asociar el grano con otros nombres mediante el uso de nombre de aliasing, como

se discute en la siguiente sección.

Frijol Nombre Aliasing


Primavera permite un grano de tener más de un nombre. Esto se puede conseguir mediante la especificación de un espacio-, comas o punto y coma separó la
lista de nombres en el nombre atributo de la haba de < bean> etiqueta. Usted puede hacer esto en lugar de, o junto con, el carné de identidad atributo. Además de
utilizar la nombre atributo, se puede utilizar el < alias> etiqueta para definir alias para los nombres de frijol de primavera. El siguiente ejemplo de configuración
muestra un simple < bean>
de configuración que define múltiples nombres para un solo grano ( app-contexto-02.xml):

<Habas ...>
<Bean id = "john" name = "john johnny, Jonathan; jim" class = "java.lang.String" /> <alias name = "john"
alias = "ion" /> </ beans>

Como se puede ver, se han definido seis nombres: uno usando el carné de identidad atributo y los otros cuatro como una lista con todos los
delimitadores nombre del bean permitidos en el nombre atributo (esto es sólo para fines de demostración y no se recomienda para el desarrollo de la
vida real). En el desarrollo de la vida real, se recomienda estandarizar el delimitador a usar para separar las declaraciones nombres de frijol dentro de
su aplicación. Uno más alias se definió utilizando la < alias> etiqueta. El siguiente ejemplo de código muestra una rutina de Java que se agarra a la
misma desde el frijol Application Context instancia de seis veces usando diferentes nombres y verifica que ellos son los mismos frijol. Además, se hace
uso del presentado anteriormente ctx.getBeansOfType (..) método para asegurarse de que sólo hay una Cuerda frijol en el contexto.

com.apress.prospring5.ch3.xml paquete;

org.springframework.context.support.GenericXmlApplicationContext importación;

java.util.Map importación;

BeanNameAliasing public class {


public void (String ... args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext (); ctx.load ( "ruta de
clase: primavera / app-contexto-02.xml"); ctx.refresh ();

Cadena s1 = (String) ctx.getBean ( "john"); Cadena s2 =


(String) ctx.getBean ( "jon"); Cadena s3 = (String) ctx.getBean (
"johnny"); Cadena s4 = (String) ctx.getBean ( "jonathan");
Cadena s5 = (String) ctx.getBean ( "jim"); Cadena s6 = (String)
ctx.getBean ( "ion");

System.out.println ((s1 s2 ==));


System.out.println ((s2 == s3));
System.out.println ((s3 == s4));

97
Capítulo 3 ■ La introducción de la COI y Di en primavera

System.out.println ((s4 == s5));


System.out.println ((s5 == s6));

Map <String, String> habas = ctx.getBeansOfType (String.class);

si (beans.size () == 1) {
System.out.println ( "Sólo hay una Cadena de frijol."); }

ctx.close (); }}

Ejecutar el código anterior se imprimirá cierto cinco veces y la “Sólo hay un Hilo” texto, la verificación de que los granos de
acceder usando diferentes nombres son, de hecho, el mismo frijol.
Puede recuperar una lista de los alias bean llamando ApplicationContext.getAliases (String) y que pasa en cualquiera de los nombres o
identificadores de los granos. La lista de alias, que no sea el que se especifica, que se obtiene es una Cuerda formación.

Se mencionó antes que con anterioridad a la primavera del 3,1 carné de identidad atributo es la misma que la identidad XML (es decir, xsd: ID), lo que significa que

los ID de frijol no podían contener caracteres especiales como el espacio-, comas o punto y coma. A partir de la primavera 3,1, xsd: string se utiliza para la carné de

identidad atribuir, por lo que la restricción anterior sobre los caracteres que se pueden utilizar se ha ido. Sin embargo, esto no quiere decir que usted puede utilizar lo

siguiente:

<Nombre de bean = "Jon johnny, Jonathan; jim" class = "java.lang.String" />

en lugar de esto:

<Bean id = "Jon johnny, Jonathan; jim" class = "java.lang.String" />

los nombre y carné de identidad valores de los atributos son tratados de manera diferente por el COI de primavera. Puede recuperar una lista de los
alias bean llamando ApplicationContext.getAliases (String) y que pasa en cualquiera de los nombres o identificadores de los granos. La lista de alias, que no
sea el que se especifica, que se obtiene es una Cuerda formación. Esto significa, en el primer caso, Jon se convertirá en la identificación, y el resto de valores
se convertirá alias.
En el segundo caso, cuando la misma cadena se utiliza como un valor para la carné de identidad atribuir, la cadena completa se convierte en un identificador único

para el grano. Esto se puede ensayar fácilmente con una configuración como la que se muestra aquí (que se encuentra en el archivo app-contexto-03.xml):

<Habas ...>
<Nombre de bean = "Jon johnny, Jonathan; jim" class = "java.lang.String" />

<Bean id = "Jon johnny, Jonathan; jim" class = "java.lang.String" /> </ beans>

y una clase principal como la que se muestra en el siguiente ejemplo de código:

com.apress.prospring5.ch3.xml paquete;

org.springframework.context.support.GenericXmlApplicationContext importación;

java.util.Arrays de importación;
java.util.Map importación;

98
Capítulo 3 ■ La introducción de la COI y Di en primavera

BeanCrazyNaming public class {


public void (String ... args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext (); ctx.load ( "ruta de
clase: primavera / app-contexto-03.xml"); ctx.refresh ();

Map <String, String> habas = ctx.getBeansOfType (String.class);

.. Beans.entrySet () corriente () forEach (b -> {

System.out.println ( "id:" + b.getKey () +


"\ n alias:" + Arrays.toString (ctx.getAliases (b.getKey ())) + "\ n"); });

ctx.close (); }}

Cuando se ejecuta, esto producirá el siguiente resultado:

ID: Jon
alias: Jonathan, jim, johnny

ID: Jon Johnny, Jonathan; alias jim:

Como se puede ver, el mapa con Cuerda frijol contiene dos granos, uno con el Jon identificador único y tres alias y uno con
el Jon johnny, Jonathan; jim identificador único y no hay alias.
Frijol nombre de alias es una bestia extraña, ya que no es algo que tiende a utilizar cuando se está construyendo una nueva aplicación. Si usted
va a tener muchos otros granos inyectan otro bean, pueden también utilizar el mismo nombre para acceder a esa frijol. Sin embargo, como su aplicación
entra en trabajo de producción y mantenimiento se deja llevar a cabo, se realizan modificaciones, y así sucesivamente, nombre del bean aliasing se
vuelve más útil.
Considere el siguiente escenario: tiene una aplicación en la que 50 frijoles, configuran utilizando la primavera, todos requieren una
implementación de la foo interfaz. Veinticinco de los granos de usar el StandardFoo
aplicación con el nombre de frijol standardFoo, y el otro 25 utiliza el SuperFoo aplicación con el SuperFoo nombre del bean. Seis
meses después de poner la aplicación en producción, decide mover los primeros 25 habas a la SuperFoo implementación. Para
ello, usted tiene tres opciones.

• La primera es cambiar la clase de implementación de la standardFoo frijol a SuperFoo.


El inconveniente de este enfoque es que usted tiene dos instancias de la SuperFoo clase por ahí cuando
realmente se necesita sólo una. Además, ahora tiene dos granos para realizar cambios cuando los cambios de
configuración.

• La segunda opción es actualizar la configuración de inyección para los 25 granos que están cambiando, que
cambia los nombres de las habas de standardFoo a SuperFoo. Este enfoque no es la forma más elegante para
proceder. Se podría realizar una búsqueda y reemplazo, pero luego revertir los cambios cuando la administración
no es feliz significa recuperar una versión antigua de la configuración de su sistema de control de versiones.

• La tercera, y más ideal, enfoque consiste en quitar (o fuera) de la definición de la standardFoo frijol y
hacer standardFoo un alias SuperFoo. Este cambio requiere un mínimo esfuerzo, y restaurar el
sistema a su configuración anterior es tan simple.

99
Capítulo 3 ■ La introducción de la COI y Di en primavera

Frijol de nomenclatura con Configuraciones de anotación

Cuando las definiciones de frijol se declaran mediante anotaciones, nombres de frijol es un poco diferente de XML, y hay cosas más interesantes que se
pueden hacer. Vamos a empezar con lo básico, sin embargo: declarar definiciones de frijol utilizando anotaciones estereotipo (@ Componente y todas
sus especialidades, tales como Servicio, depósito, y
Controlador).
Considera lo siguiente Cantante clase:

com.apress.prospring5.ch3.annotated paquete;

org.springframework.stereotype.Component importación;

@Componente

El cantante public class {

Cadena lírica privada = "Hemos encontrado un mensaje en una botella que estábamos bebiendo";

public void cantar () {


System.out.println (letra); }}

Esta clase contiene la declaración de un grano de tipo singleton Cantante escrita con las teclas @ Componente
anotación. Los @ Componente anotación no tiene ningún argumento, por lo que el contenedor de primavera IoC decide un identificador único para el grano.
La convención utilizada en este caso es nombrar el grano, como la propia clase, pero la conversión a minúsculas la primera letra. Esto significa que el grano
será nombrado cantante. Esta convención es respetado por otras anotaciones estereotipo también. Para probar esto, la clase puede utilizarse el siguiente:

com.apress.prospring5.ch3.annotated paquete;

org.springframework.context.support.GenericXmlApplicationContext importación;

java.util.Arrays de importación;

java.util.Map importación;

AnnotatedBeanNaming public class {

public void (String ... args) {


GenericXmlApplicationContext ctx =
nuevo GenericXmlApplicationContext (); ctx.load ( "ruta de clase:
primavera / app-contexto-annotated.xml"); ctx.refresh ();

Map <String, Cantante> = habas


ctx.getBeansOfType (Singer.class);

.. Beans.entrySet () corriente () forEach (b ->


System.out.println ( "id:" + b.getKey ())); ctx.close (); }}

100
Capítulo 3 ■ La introducción de la COI y Di en primavera

los App-contexto-annotated.xml archivo de configuración contiene solamente una declaración de exploración componente para com.apress.prospring5.ch3.anno
por lo que no se mostrará de nuevo. Cuando se ejecuta la clase anterior, la siguiente salida se imprime en la consola:

ID: cantante

Por lo tanto, el uso de @ Componente ( "cantante") es equivalente a la anotación de la Cantante clase con @ Componente. Si desea asignar un nombre
diferente del frijol, el @ Componente anotación debe recibir el nombre del bean como un argumento.

com.apress.prospring5.ch3.annotated paquete;

org.springframework.stereotype.Component importación;

@Component ( "John Mayer")


Singer public class {

Cadena lírica privada = "Abajo hay debajo de nosotros, bajo las nubes";

public void cantar () {


System.out.println (letra); }}

Como era de esperar, si AnnotatedBeanNaming es ejecutado, la siguiente salida se produce:

ID: John Mayer

Pero, ¿qué pasa con los alias? A medida que el argumento a favor de la @ Componente anotación se convierte en el identificador único para el frijol,
frijol aliasing no es posible cuando se declara el grano de esta manera. Aquí es donde la configuración de Java viene al rescate. Vamos a considerar la
siguiente clase, que contiene una clase de configuración estática definida dentro de ella (sí, Primavera permite esto, y estamos siendo práctica aquí,
manteniendo toda la lógica en el mismo archivo):

com.apress.prospring5.ch3.config paquete;

com.apress.prospring5.ch3.annotated.Singer importación;
org.springframework.context.annotation.AnnotationConfigApplicationContext importación;
org.springframework.context.annotation.Bean importación; org.springframework.context.annotation.Configuration
importación; org.springframework.context.support.GenericApplicationContext importación;
org.springframework.context.support.GenericXmlApplicationContext importación;

java.util.Arrays de importación;
java.util.Map importación;

AliasConfigDemo public class {

@Configuración
public static class {AliasBeanConfig
@Frijol
Cantante pública () {

101
Capítulo 3 ■ La introducción de la COI y Di en primavera

volver nuevo Singer (); }}

public void (String ... args) {


GenericApplicationContext ctx =
nuevo AnnotationConfigApplicationContext (AliasBeanConfig.class);

Map <String, Cantante> habas = ctx.getBeansOfType (Singer.class); .. Beans.entrySet


() corriente () forEach (b ->
System.out.println ( "id:" + b.getKey ()
+ "\ n" alias:
+ Arrays.toString (ctx.getAliases (b.getKey ())) + "\ n")
);

ctx.close (); }}

Esta clase contiene una definición de frijol para un bean de tipo Cantante declarado por la anotación de la cantante()
método con el @ Frijol anotación. Cuando no se proporciona ningún argumento a favor de esta anotación, el identificador único de la haba, su carné de identidad, se

convierte en el nombre del método. Por lo tanto, cuando se ejecuta la clase anterior, obtenemos el siguiente resultado:

alias cantante:

Identificación:

Para declarar alias, hacemos uso de la nombre atributo de la @ Frijol anotación. Este atributo es el uno por defecto para esta anotación,
lo que significa en este caso que se declara el grano por la anotación de la cantante()
método con @ Frijol, @Bean ( "cantante"), o @ Bean (name = "cantante") dará lugar al mismo resultado. El contenedor del resorte IoC creará un bean de tipo Cantante
y con la cantante CARNÉ DE IDENTIDAD.
Si el valor de este atributo es una cadena que contiene un separador-alias específico (espacio, coma, punto y coma), la cadena se convertirá en el ID del
grano. Sin embargo, si el valor porque es una matriz de cadenas, el primero se convierte en el carné de identidad y los otros se convierten en alias. Modificar la
configuración de frijol como se muestra aquí:

@Configuración
public static class {AliasBeanConfig
@Bean (nombre = { "John Mayer", "John", "Jonathan", "Johnny"}) Cantante
pública () {
volver nuevo Singer (); }}

Cuando se ejecuta el AliasConfigDemo clase, la salida cambiará a lo siguiente:

ID: John Mayer


alias Jonathan, johnny, john

102
Capítulo 3 ■ La introducción de la COI y Di en primavera

Cuando se trata de alias, en la primavera del 4,2 al @ AliasFor se introdujo anotación. Esta anotación se utiliza para declarar alias para los
atributos de anotación, y la mayoría de las anotaciones Spring hacer uso de ella. Por ejemplo, el @ Frijol anotación tiene dos atributos, nombre y valor, el
cual se declaran como alias para el uno al otro. El uso de esta anotación, que son alias explícitos. El siguiente fragmento de código es una
instantánea de la @ Frijol código de anotación y se toma desde el repositorio oficial de Primavera GitHub. El código y la documentación que no son
relevantes en el momento se han omitido: 4

org.springframework.context.annotation paquete;

java.lang.annotation.Documented importación;
java.lang.annotation.ElementType importación;
java.lang.annotation.Retention importación;
java.lang.annotation.RetentionPolicy importación;
java.lang.annotation.Target importación;

org.springframework.core.annotation.AliasFor importación;
...
@Target ({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Retention
(RetentionPolicy.RUNTIME) @Documented

@interface pública frijol {


@AliasFor ( "nombre") Valor de la cadena () {}
predeterminado;

@AliasFor ( "valor") String name () {}


predeterminado;

...
}

He aquí un ejemplo. Declarar una anotación llamada @ Premio que se puede utilizar en Cantante casos, por supuesto.

com.apress.prospring5.ch3.annotated paquete;

org.springframework.core.annotation.AliasFor importación;

Premio @interface pública {

@AliasFor ( "premio") Valor de la cadena () {}


predeterminado;

@AliasFor ( "valor") premio String () {}


predeterminado; }

4 Se puede ver en la implementación completa aquí: https://github.com/spring-projects/spring-framework/blob/ maestro / primavera-core / src /

main / java / org / Spring Framework / core / anotación / AliasFor.java .

103
Capítulo 3 ■ La introducción de la COI y Di en primavera

El uso de esta anotación, se puede modificar el Cantante clase como esta:

com.apress.prospring5.ch3.annotated paquete;

org.springframework.beans.factory.annotation.Qualifier importación;
org.springframework.stereotype.Component importación;

@Component ( "John Mayer")


@Award (premio = { "Grammy", "disco de platino"}) Singer
public class {

Cadena lírica privada = "Hemos encontrado un mensaje en una botella que estábamos bebiendo";

public void cantar () {


System.out.println (letra); }}

La anotación anterior es equivalente a @ Premio (valor = { "Grammy", "disco de platino"}) y para


@Award ({ "Grammy", "disco de platino"}).
Pero algo más interesante se puede hacer con el @ AliasFor Anotación: alias de atributos meta-anotaciones pueden ser declaradas. En el
siguiente fragmento de código, declaramos una especialización para el @ Premio
anotación que declara un atributo llamado nombre, que es un alias para el valor atributo de la @ Premio
anotación. Y lo hacemos porque queremos que sea obvio que el argumento es un identificador único de frijol.

com.apress.prospring5.ch3.annotated paquete;

org.springframework.core.annotation.AliasFor importación;

@Premio

@interface pública trofeo {

@AliasFor (annotation = Award.class, atributo = "valor") String name ()


predeterminado {}; }

Por lo tanto, en lugar de escribir la Cantante clase como esta:

com.apress.prospring5.ch3.annotated paquete;

org.springframework.stereotype.Component importación;

@Component ( "John Mayer")


@Award (valor = { "Grammy", "disco de platino"}) Singer
public class {

Cadena lírica privada = "Hemos encontrado un mensaje en una botella que estábamos bebiendo";

public void cantar () {


System.out.println (letra); }}

104
Capítulo 3 ■ La introducción de la COI y Di en primavera

se puede escribir así:

com.apress.prospring5.ch3.annotated paquete;

@Component ( "John Mayer")


@Trophy (nombre = { "Grammy", "disco de platino"}) Singer
public class {

Cadena lírica privada = "Hemos encontrado un mensaje en una botella que estábamos bebiendo";

public void cantar () {


System.out.println (letra); }}

La creación de alias para los atributos de anotaciones usando otra anotación @ AliasFor tiene sus limitaciones. @ AliasFor no puede ser

utilizado en cualquier anotación estereotipo (@ Componente y sus especializaciones). la razón es que el manejo especial de estos valor atributos estaba

en su lugar años antes de @ AliasFor fue inventado. En consecuencia, debido a problemas de compatibilidad con versiones anteriores, simplemente no

es posible utilizar @ AliasFor

con tales atributos de valor. Al escribir código para hacer tan (aliasing valor los atributos de anotaciones estereotipo), no hay errores de compilación se le

aparecen a usted, y el código, incluso podría funcionar, pero ningún argumento proporcionado por el alias serán ignorados. lo mismo vale para el

@Índice anotación también.

Descripción del modo de la haba de instancias


Por defecto, todos los granos en la primavera son únicos. Este medio de resorte mantiene una única instancia de la haba, todos los objetos
dependientes utilizan la misma instancia, y todas las llamadas a ApplicationContext.getBean () devolver la misma instancia. Hemos demostrado esto en
la sección anterior, en el que pudimos utilizar la comparación de identidad (==) en lugar de la equals () comparación para comprobar si los granos eran el
mismo.
El termino semifallo se usa indistintamente en Java para hacer referencia a dos conceptos distintos: un objeto que tiene una única instancia dentro
de la aplicación y el patrón de diseño Singleton. Nos referimos al primer concepto como una semifallo y para el patrón Singleton como Singleton. El patrón
de diseño Singleton fue popularizado en el seminal Patrones de diseño: Elementos de software orientado a objetos reutilizables por Erich Gamma et al.
(Addison-Wesley,
1994). El problema surge cuando la gente confunde la necesidad de instancias único con la necesidad de aplicar el patrón Singleton. El siguiente
fragmento de código muestra una implementación típica del patrón Singleton en Java:

com.apress.prospring5.ch3 paquete;

public class Singleton {


Singleton instancia estática privada;

estática {
instancia = new Singleton (); }

public static Singleton getInstance () {


volver ejemplo; }}

105
Capítulo 3 ■ La introducción de la COI y Di en primavera

Este patrón logra su objetivo de que le permite mantener y acceder a una sola instancia de una clase a través de su aplicación, pero lo hace a
expensas de un mayor acoplamiento. El código de aplicación siempre debe tener conocimiento explícito de la clase Singleton con el fin de obtener el
ejemplo- por completo la eliminación de la capacidad de codificar a las interfaces.

En realidad, el patrón Singleton es en realidad dos patrones en uno. La primera, y deseado, modelo implica el mantenimiento de una sola instancia de
un objeto. El segundo, y menos deseable, es un patrón para la búsqueda de objeto que elimina por completo la posibilidad de utilizar interfaces. Utilizando el
patrón Singleton también hace que sea difícil de extraerse implementaciones de manera arbitraria porque la mayoría de los objetos que requieren la instancia
Singleton Singleton acceder al objeto directamente. Esto puede causar todo tipo de dolores de cabeza cuando se está tratando a la unidad de probar la
aplicación, ya que son incapaces de sustituir el Singleton con una maqueta para realizar pruebas.

Afortunadamente, con la primavera se puede tomar ventaja del modelo de instancias singleton sin tener que trabajar todo el patrón de diseño Singleton.
Todos los frijoles en la primavera son, por defecto, creada como instancias Singleton, y la primavera se utilizan las mismas instancias para cumplir con todas las
peticiones de que Bean. Por supuesto, la primavera no se limita sólo a la utilización de la instancia Singleton; todavía puede crear una nueva instancia del grano
para satisfacer cada dependencia y cada llamada a getBean (). Se hace todo esto sin ningún impacto en el código de aplicación, y por esta razón, nos gustaría
hacer referencia a la primavera como el modo de ejemplificación agnóstico. Este es un concepto poderoso. Si usted comienza con un objeto que es un producto
único, pero luego descubre que no es muy adecuado para el acceso multi-hilo, se puede cambiar a un más de un elemento (prototipo) sin afectar a cualquiera de
su código de aplicación.

Aunque cambiar el modo de creación de instancias de bean no afectará su código de aplicación, sí causa algunos problemas si se basan en las

interfaces del ciclo de vida de la primavera. Cubrimos esto con más detalle en el capítulo 4 .

Cambiar el modo de ejemplificación de Singleton a más de un elemento es simple. Los siguientes fragmentos de configuración presentes cómo se
hace esto en XML y utilizando anotaciones:

<! - aplicación de contexto xml.xml ->


<habas ...>
<Bean id = clase "más de un elemento" = "com.apress.prospring5.ch3.annotated.Singer"
scope = "prototipo" c: _0 = "John Mayer" /> </ beans>

\\ Singer.java
com.apress.prospring5.ch3.annotated paquete;

org.springframework.beans.factory.annotation.Value importación;
org.springframework.context.annotation.Scope importación;
org.springframework.stereotype.Component importación;

@Component ( "más de un elemento")


@Scope ( "prototipo") Singer public
class {
private String nombre = "desconocido";

El cantante pública (@Valor ( "John Mayer") String nombre) {


this.name = nombre; }}

106

Você também pode gostar