Sei sulla pagina 1di 66

Desarrollo de Aplicaciones

con Spring
2. Contenedor IoC
Introduccin
Creacin de objetos
Inyeccin de dependencias.
Paquetes
org.springframework.beans
org.springframework.context
BeanFactory
Framework de configuracin
Funcionalidad Bsica
ApplicationContext
Funcionalidad Empresarial
Integracion AOP
Internacionalizacin
Eventos
Contextos especficos (WebApplicationContext)
Application Context
StandAlone
ClassPathXmlApplicationContext
FileSystemXmlApplicationContext
Aplicaciones Web
No es necesario normalmente escribir cdigo
Se escribe en el web.xml
Vista bsica
Configuracin
Ficheros XML
Anotaciones JAVA
Cdigo JAVA
Ficheros XML
<?xml version="1.0" encoding="UTF-8"?>
<beans 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-3.0.xsd">

<bean id="..." class="...">


<!-- collaborators and configuration for this bean go here
<property name="..." value="..." />
</bean>

<bean id="..." class="...">


<!-- collaborators and configuration for this bean go here -->
</bean>

<!-- more bean definitions go here -->

</beans>
Crear Contexto StandAlone
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {"services.xml", "daos.xml"});
Terminar Contexto StandAlone
ctx.registerShutdownHook();
Importar Metadatos
<beans>

<import resource="services.xml"/>
<import resource="resources/messageSource.xml"/>
<import resource="/resources/themeSource.xml"/>

<bean id="bean1" class="..."/>


<bean id="bean2" class="..."/>

</beans>
Mtodo getBean()
// create and configure beans
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {"services.xml", "daos.xml"});

// retrieve configured instance


PetStoreServiceImpl service = context.getBean("petStore",
PetStoreServiceImpl.class);

// use configured instance


List userList service.getUsernameList();
Beans
Deben tener un nombre nico
Pueden existir alias
No es necesario explicitamente
Beans Instanciar
Instancias por constructor
No es necesario que no tenga argumentos
(JavaBean).
Instanciar con metodo statico
Permite usar clases heredadas de tipo Factory
Instanciar con metodo de instancia tipo Factory
Permite usar un bean como Fabrica de beans
Se utiliza normalmente para reutilizar cdigo
heredado
Beans Instanciar - Ejemplos
<bean id="exampleBean" class="examples.ExampleBean"/>

<bean name="anotherExample" class="examples.ExampleBeanTwo"/>

<bean id="clientService"
class="examples.ClientService"
factory-method="createInstance"/>

<!-- the factory bean, which contains a method called createInstance() -->
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
<!-- inject any dependencies required by this locator bean -->
</bean>

<!-- the bean to be created via the factory bean -->


<bean id="clientService"
factory-bean="serviceLocator"
factory-method="createClientServiceInstance"/>
Dependencias -IoC
Dos maneras principales
Inyeccin por constructor
Inyeccion por mtodos setter
Constructor - Ejemplos
<beans>
<bean id="foo" class="x.y.Foo">
<constructor-arg ref="bar"/>
<constructor-arg ref="baz"/>
</bean>

<bean id="bar" class="x.y.Bar"/>


<bean id="baz" class="x.y.Baz"/>

</beans>
Constructor Ejemplos
Typado explicito
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg type="int" value="7500000"/>
<constructor-arg type="java.lang.String" value="42"/>
</bean>
Constructor Ejemplos
Indice explicito
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg index="0" value="7500000"/>
<constructor-arg index="1" value="42"/>
</bean>
Constructor - Ejemplos
Nombre de parametro
Es necesario compilar con informacin de debug
Existe la posibilidad de usar la anotacion
@ConstructorProperties
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg name="years" value="7500000"/>
<constructor-arg name="ultimateanswer" value="42"/>
</bean>

@ConstructorProperties({"years", "ultimateAnswer"})
public ExampleBean(int years, String ultimateAnswer) {
this.years = years;
this.ultimateAnswer = ultimateAnswer;
}
Metodo setter
Es el mtodo ms usado
public class SimpleMovieLister {

// the SimpleMovieLister has a dependency on the MovieFinder


private MovieFinder movieFinder;

// a setter method so that the Spring container can 'inject' a MovieFinder


public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}

// business logic that actually 'uses' the injected MovieFinder is omitted...


}
Metodo setter Ejemplos

<bean id="exampleBean" class="examples.ExampleBean">

<!-- setter injection using the nested <ref/> element -->


<property name="beanOne"><ref bean="anotherExampleBean"/></property>

<!-- setter injection using the neater 'ref' attribute -->


<property name="beanTwo" ref="yetAnotherBean"/>
<property name="integerProperty" value="1"/>
</bean>

<bean id="anotherExampleBean" class="examples.AnotherBean"/>


<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
Posibilidades IoC
Valores estandar (String, int)...
Referencias a otros beans
Beans Internos
Colecciones
Valores Estadar
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-
method="close">

<!-- results in a setDriverClassName(String) call -->


<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mydb"/>
<property name="username" value="root"/>
<property name="password" value="masterkaoli"/>
</bean>
<bean id="mappings"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">

<!-- typed as a java.util.Properties -->


<property name="properties">
<value>
jdbc.driver.className=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mydb
</value>
</property>
</bean>
Referencia a otros Beans
<ref bean="someBean"/>

<ref local="someBean"/> <!-- Validacin XML


Beans Internos
Son anonimos y se crean en el momento de crear el
padre.
Simpre son de tipo Prototype
<bean id="outer" class="...">
<!-- instead of using a reference to a target bean, simply define the target bean
inline -->
<property name="target">
<bean class="com.example.Person"> <!-- this is the inner bean -->
<property name="name" value="Fiona Apple"/>
<property name="age" value="25"/>
</bean>
</property>
</bean>
Colecciones
List, Map, Set, Properties
Los valores posibles, tanto para claves como para
valores pueden ser:
bean | ref | idref | list | set | map | props | value | null
Properties
<bean id="moreComplexObject" class="example.ComplexObject">
<!-- results in a setAdminEmails(java.util.Properties) call -->
<property name="adminEmails">
<props>
<prop key="administrator">administrator@example.org</prop>
<prop key="support">support@example.org</prop>
<prop key="development">development@example.org</prop>
</props>
</property>
</bean>
List

<bean id="moreComplexObject" class="example.ComplexObject">


<!-- results in a setSomeList(java.util.List) call -->
<property name="someList">
<list>
<value>a list element followed by a reference</value>
<ref bean="myDataSource" />
</list>
</property>
</bean>
Map
<bean id="moreComplexObject" class="example.ComplexObject">
<!-- results in a setSomeMap(java.util.Map) call -->
<property name="someMap">
<map>
<entry key="an entry" value="just some string"/>
<entry key ="a ref" value-ref="myDataSource"/>
</map>
</property>
</bean>
Set
<bean id="moreComplexObject" class="example.ComplexObject">
<!-- results in a setSomeSet(java.util.Set) call -->
<property name="someSet">
<set>
<value>just some string</value>
<ref bean="myDataSource" />
</set>
</property>
</bean>
Prctica 1
Realizar una aplicacin standalone, con dos beans.
Un Bean dao que implemente la interface
TercerosDAO propuesta.
Los valores devueltos no se cogern de ninguna base
de datos, sino que se debern pasar como
configuracin en el contexto Spring.
Un Bean que implemente la interface TercerosBO,
que sume las ventas de todos los vendedores.
Debera usar el TercerosDAO.
Prctica 1
Se deber crear una clase Main que llame al
bean TercerosBO y saque por pantalla las ventas
totales
depends-on
Dependencias con las que no se tiene una
referencia.
<bean id="beanOne" class="ExampleBean" depends-on="manager,accountDao">
<property name="manager" ref="manager" />
</bean>

<bean id="manager" class="ManagerBean" />


<bean id="accountDao" class="x.y.jdbc.JdbcAccountDao" />
Inicializacin lazy
Por defecto todos los Beans Singleton se
inicializan al iniciar el ApplicationContext
Suele ser la mejor opcion, para ver posibles errores al
iniciar
Se puede sobreescribir
<bean id="lazy" class="com.foo.ExpensiveToCreateBean" lazy-init="true"/>

<bean name="not.lazy" class="com.foo.AnotherBean"/>

<beans default-lazy-init="true">
<!-- no beans will be pre-instantiated... -->
</beans>
Autoconexin
Es poible que spring compruebe qu beans necesita un bean
determinado y establecerselo sin necesidad de definirlo explicitamente.
En algunos casos puede ser peligroso
Es preferible realizar alguna convencin de nombres para los beans
Atributo autowire (bean)
no Por defecto, no realiza autoescritura
byName Por nombre (metodo setter)
byType Por tipo, si existieran dos mtodos setter con el mismo produce
excepcin
constructor Igual que por tipo pero en el constructor
Atributo autowire-candidate
Excluye un bean como candidato para autoeconexin
Ambito de los Bean
singleton Por defecto, solo se crea uno por
contenedor IoC
prototype Se crea uno por peticin del bean
request Uno por HTTP Request (Solo para web
aplication context)
session Uno por HTTP Session (Solo para web
application context)
Prototype
Se crea uno siempre que se realiza una peticin al
bean
Por una propiedad
llamada a getBean().
No maneja todo el ciclo de vida.
Solo maneja el ciclo de vida de inicializacin
Nunca maneja el ciclo de vida de destruccin.
Singleton Prototype
Si un bean singleton, tiene una referencia a un
bean prototype, solo se crear uno para el bean.
Cuando un bean singleton necesita una nueva
instancia de un bean cada vez se debe usar
method-injection
Sigleton Prototype 1
public class CommandManager implements ApplicationContextAware {

private ApplicationContext applicationContext;

public Object process(Map commandState) {


// grab a new instance of the appropriate Command
Command command = createCommand();
// set the state on the (hopefully brand new) Command instance
command.setState(commandState);
return command.execute();
}

protected Command createCommand() {


// notice the Spring API dependency!
return this.applicationContext.getBean("command", Command.class);
}

public void setApplicationContext(ApplicationContext applicationContext)


throws
BeansException {
this.applicationContext = applicationContext;
}
}
Singleton Prototype - 1
Se debe implementer interfaces Spring
Hay que crear cdigo que no es de negocio para
conseguir un nuevo bean cada vez.
Singleton Prototype 2
public abstract class CommandManager {

public Object process(Object commandState) {


// grab a new instance of the appropriate Command interface
Command command = createCommand();
// set the state on the (hopefully brand new) Command instance
command.setState(commandState);
return command.execute();
}

// okay... but where is the implementation of this method?


protected abstract Command createCommand();
}

<public|protected> [abstract] <return-type> theMethodName(no-arguments);


Singleton Prototype - 2
<!-- a stateful bean deployed as a prototype (non-singleton) -->
<bean id="command" class="fiona.apple.AsyncCommand" scope="prototype">
<!-- inject dependencies here as required -->
</bean>

<!-- commandProcessor uses statefulCommandHelper -->


<bean id="commandManager" class="fiona.apple.CommandManager">
<lookup-method name="createCommand" bean="command"/>
</bean>
Singleton Prototype 2
No hay que importar nada de Spring
(independencia total del framework).
No hay que escribir cdigo adicional que no es de
negocio.
Dependencias a beans con
ambitos (session, request)
Es necesario usar un proxy para acceder al bean.
<aop:scoped-proxy/>
Crea un proxy de la clase
Necesita la librera CGLIB
<aop:scoped-proxy proxy-target-
class="false"/>
No necesita librera adicional
Es necesario que la clase implemente interfaces y que
las dependencias de otros beans accedan por alguna de
sus interfaces.

Retrollamadas de Ciclo de vida


Mtodos a los que llama el framework al construir o
destruir beans
Retrollamadas de inicializacin
Retrollamadas de destruccin
Retrollamadas de Inicializacin
Mtodo acoplado
org.springframework.beans.factory.InitializingBean
void afterPropertiesSet() throws Exception;
Mtodo desacoplado
<bean id="exampleInitBean" class="examples.ExampleBean"
init-method="init"/>

Retrollamadas de Destruccin
Mtodo acoplado
org.springframework.beans.factory.DisposableBean
void destroy() throws Exception;
Mtodo desacoplado
<bean id="exampleInitBean"
class="examples.ExampleBean" destroy-
method="cleanup"/>

Mtodos por defecto
Desacoplados
<beans default-init-method="init" default-destroy-method=cleanup >

<bean id="blogService" class="com.foo.DefaultBlogService">


<property name="blogDao" ref="blogDao" />
</bean>

</beans>
Anotaciones
@PostConstruct
@PreDestroy
Interfaces Aware
Interfaces que, si algn bean las implementa, el
framework llama a sus mtodos para realizar o
establecer alguna propiedad.
Se pierde el desacople con el framework
ApplicationContextAware
Referencia el ApplicationContext.
public interface ApplicationContextAware {

void setApplicationContext(ApplicationContext applicationContext) throws


BeansException;
}
BeanNameAware
Establece el nombre del bean.
public interface BeanNameAware {

void setBeanName(string name) throws BeansException;


}
Herencia en Beans
Es posible heredar la configuracin de un bean en
otro.
El bean hijo hereda toda la configuracin del padre y,
esta se puede sobreescribir o aumentar.
Atributo parent
Si el padre no se quiere instanciar, normalmente por
ser abstracto es necesario incluir el atributo
abstract=true
No es necesaria una clase para los beans abstactos.
Herencia de Beans - Ejemplo
<bean id="inheritedTestBean" abstract="true"
class="org.springframework.beans.TestBean">
<property name="name" value="parent"/>
<property name="age" value="1"/>
</bean>

<bean id="inheritsWithDifferentClass"
class="org.springframework.beans.DerivedTestBean"
parent="inheritedTestBean" init-method="initialize">

<property name="name" value="override"/>


<!-- the age property value of 1 will be inherited from parent -->

</bean>
Extension Points
BeanPostProcessor
BeanFactoryPostProcessor
FactoryBean
BeanFactoryPostProcessor
Cambian la configuracin de los Beans
Existen algunos implementados de uso general.
PropertyPlaceholderConfigurer
PropertyOverrideConfigurer
PropertyPlaceholderConfigurer
Configura cualquier literal del fichero de
configuracin a travs de ficheros de propiedades.

<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations" value="classpath:com/foo/jdbc.properties"/>
</bean>

<bean id="dataSource" destroy-method="close"


class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
PropertyOverrideConfigurer
Configura los beans y sobreescribe las propiedades
que estn en un fichero de propiedades.
Las propiedades en el fichero de propiedades debe
estar en la forma:
beanName.property=value
Internacionalizacion
ApplicationContext implementa
MessageResource
El bean se debe llamar messageResource
Varias clases lo implementan:
ResourceBundleMessageSource
ReloadableResourceBundleMessageSource
Es compatible con i18n
Usar MessageSource
Usando el ApplicationContext
ctx.getMessage(...)
Usando IoC
Implementando MessageSourceAware
Usando IoC
<beans>
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>format</value>
<value>exceptions</value>
<value>windows</value>
</list>
</property>
</bean>
<bean id="example" class="com.foo.Example">
<property name="messages" ref="messageSource"/>
</bean>
</beans>
Configuracion Web Container
Para el application context crear un listener con la
clase ContextLoaderListener
Adems si se van a usar Beans de ambito session o
request hay que crear un listener con la clase
RequestContextListener
Ejemplo web.xml
<web-app>
...
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/daoContext.xml /WEB-INF/applicationContext.xml</param-value>
</context-param>

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-
class>
</listener>

<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
...
</web-app>
Practica 2
Internacionalizacin,
Propiedades, Herencia
Con la aplicacin de la prctica 1, internacionalizar
el mensaje de salida y sacarlo en varios idiomas.
Separar el fichero de configuracin en varios (uno
general, uno de BO y otro DAO).
Sacar a fichero de propiedades el nombre de la
clase que implementa el DAO.
Todas nuestros beans, debern tener acceso a los
mensajes, por tanto, deberan todas ellas tener un
messageSource. Esto se puede realizar con la
herencia de beans.
Practica 3 Probar el autowire
para TercerosBO
Activar autoWire para tercerosBO y comprobar que
funciona la inyeccin del bean tercerosDAO
Practica 4 Pasar a proyecto
WEB
Pasar el proyecto a proyecto WEB (Servlet 2.5)
Configurar el fichero web.xml
Configurar librerias
Comprobar en el log que arranca los beans.