Como configurar o Spring?

17 respostas
D

Olá pessoal!

Hoje eu encuquei que ia aprender a usar o Spring para integrar com o Hibernate. Bem, estou dando uma olhada em alguns livros (principalmente o Spring in Action, Second Edition), mas a configuração do Spring é meio vaga. Talvez seja porque eu já pulei direto para a integração com o hibernate. Enfim, já fiz algumas coisinhas, mas está dando um null pointer exception na hora de salvar um objeto no banco, me parece que ele não está entendendo minha configuração pois não é injetada a SessionFactory dentro do HibernateDaoSupport . Estou postando em anexo o meu projeto do NetBeans beleza? Precisa configurar a as libs para usar o Spring.

Quem pude me dar uma luz eu agradeço!

Abraços!

P.S. Desculpa a burrice, é que estou começando hehehehehe :smiley:

17 Respostas

_

Não uso netbeans.

Que tal postar só o seu arquivo de configuração do Spring?

De qualquer forma, sua aplicação é web? Se sim, você adicionou os ServletListeners do Spring ao web.xml?

D

Olá LIPE

Eis aqui o spring.xml

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

<!--
    Document   : spring.xml
    Created on : October 16, 2007, 1:53 PM
    Author     : David Buzatto
    Description: Configuração do Spring
-->

<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-2.0.xsd">
    
    <!-- Obtém o arquivo properties -->
    <bean id="propertyConfigurer"
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="hibernate.properties" />
    </bean>
    
    <!-- Data Source -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
        
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost/testeSpring"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
        <property name="initialSize" value="5"/>
        <property name="maxActive" value="10"/>
        
    </bean>
    
    <!-- Session Factory -->
    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        
        <property name="dataSource" ref="dataSource" />
        
        <!-- Classes -->
        <property name="annotatedClasses">
            <list>
                <value>testandospring.Cliente</value>
            </list>
        </property>
        
        <property name="hibernateProperties">
            <props>
                <!-- Buscando no arquivo de properties -->
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
            </props>
        </property>
    </bean>
    
    <!-- Template do Hibernate -->
    <bean id="hibernateTemplate"
        class="org.springframework.orm.hibernate3.HibernateTemplate">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
    
    <!-- Configurando os Daos -->
    <bean id="clienteDao" class="testandospring.HibernateClienteDao">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
    
</beans>

E minha classe de teste

public class Teste {
    
    public static void main( String[] args ) {
        
        Cliente c = new Cliente();
        c.setNome( "David" );
        c.setSobrenome( "Buzatto" );
        
        Resource configuration =
                new ClassPathResource("testandospring/spring.xml");
        
        BeanFactory factory =
                new XmlBeanFactory( configuration );
        HibernateClienteDao d =
                ( HibernateClienteDao) factory.getBean("clienteDao");
        
        new HibernateClienteDao().salvar( c );
    }
    
}

Quanto a ser aplicação Web, ela irá ser hehehe. É que eu queria testar o funcionamento antes de partir para a web. É só uma aplicação de teste para eu aprender a tecnologia. Vc poderia então me falar o que eu devo fazer quando foir uma aplicação web ou não? Quais listener devo configurar no web.xml? Mais uma pergunta :D A configuração do spring precisa ser carregada sempre quando for utilizá-lo ou é apenas uma vez na carga da aplicação?

Muito obrigado!

_

O mapeamento parece correto.

Perguntas:
1. A classe HibernateClienteDao extende HibernateDaoSupport?
2. Aparece o log da inicialização da session factory?

Quanto às suas perguntas: 1. o web.xml deve conter o seguinte:
<context-param>
    	<param-name>contextConfigLocation</param-name>
    	<param-value>classpath:/conf/applicationContext.xml, classpath:/conf/applicationContext-DAOs.xml, classpath:/conf/applicationContext-Services.xml</param-value>
    </context-param>

	<!-- para session scoped beans -->
	<listener>
		<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
	</listener>
    
    <listener>
    	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
2. Apenas uma vez.
D

Olá de novo LIPE

Estende sim, dê uma olhada

public class HibernateClienteDao extends HibernateDaoSupport {
    
    public void salvar( Cliente c ) {
        getHibernateTemplate().saveOrUpdate( c );
    }
    
}

Olha o log

17/10/2007 12:22:33 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [testandospring/spring.xml]
17/10/2007 12:22:34 org.hibernate.cfg.annotations.Version <clinit>
INFO: Hibernate Annotations 3.2.1.GA
17/10/2007 12:22:34 org.hibernate.cfg.Environment <clinit>
INFO: Hibernate 3.2.2
17/10/2007 12:22:34 org.hibernate.cfg.Environment <clinit>
INFO: loaded properties from resource hibernate.properties: {hibernate.connection.driver_class=com.mysql.jdbc.Driver, hibernate.cache.provider_class=org.hibernate.cache.HashtableCacheProvider, hibernate.max_fetch_depth=1, hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect, hibernate.jdbc.use_streams_for_binary=true, hibernate.format_sql=true, hibernate.query.substitutions=yes 'Y', no 'N', hibernate.proxool.pool_alias=pool1, hibernate.connection.username=root, hibernate.cache.region_prefix=hibernate.test, hibernate.connection.url=jdbc:mysql://localhost/testeSpring, hibernate.bytecode.use_reflection_optimizer=false, hibernate.connection.password=****, hibernate.jdbc.batch_versioned_data=true, hibernate.connection.pool_size=1}
17/10/2007 12:22:34 org.hibernate.cfg.Environment <clinit>
INFO: using java.io streams to persist binary types
17/10/2007 12:22:34 org.hibernate.cfg.Environment buildBytecodeProvider
INFO: Bytecode provider name : cglib
17/10/2007 12:22:34 org.hibernate.cfg.Environment <clinit>
INFO: using JDK 1.4 java.sql.Timestamp handling
17/10/2007 12:22:34 org.springframework.orm.hibernate3.LocalSessionFactoryBean buildSessionFactory
INFO: Building new Hibernate SessionFactory
17/10/2007 12:22:34 org.hibernate.cfg.AnnotationBinder bindClass
INFO: Binding entity from annotated class: testandospring.Cliente
17/10/2007 12:22:34 org.hibernate.cfg.annotations.EntityBinder bindTable
INFO: Bind entity testandospring.Cliente on table Cliente
17/10/2007 12:22:34 org.hibernate.connection.ConnectionProviderFactory newConnectionProvider
INFO: Initializing connection provider: org.springframework.orm.hibernate3.LocalDataSourceConnectionProvider
17/10/2007 12:22:35 org.hibernate.cfg.SettingsFactory buildSettings
INFO: RDBMS: MySQL, version: 5.0.15-nt
17/10/2007 12:22:35 org.hibernate.cfg.SettingsFactory buildSettings
INFO: JDBC driver: MySQL-AB JDBC Driver, version: mysql-connector-java-5.0.4 ( $Date: 2006-10-19 17:47:48 +0200 (Thu, 19 Oct 2006) $, $Revision: 5908 $ )
17/10/2007 12:22:35 org.hibernate.dialect.Dialect <init>
INFO: Using dialect: org.hibernate.dialect.MySQLDialect
17/10/2007 12:22:35 org.hibernate.transaction.TransactionFactoryFactory buildTransactionFactory
INFO: Using default transaction strategy (direct JDBC transactions)
17/10/2007 12:22:35 org.hibernate.transaction.TransactionManagerLookupFactory getTransactionManagerLookup
INFO: No TransactionManagerLookup configured (in JTA environment, use of read-write or transactional second-level cache is not recommended)
17/10/2007 12:22:35 org.hibernate.cfg.SettingsFactory buildSettings
INFO: Automatic flush during beforeCompletion(): disabled
17/10/2007 12:22:35 org.hibernate.cfg.SettingsFactory buildSettings
INFO: Automatic session close at end of transaction: disabled
17/10/2007 12:22:35 org.hibernate.cfg.SettingsFactory buildSettings
INFO: JDBC batch size: 15
17/10/2007 12:22:35 org.hibernate.cfg.SettingsFactory buildSettings
INFO: JDBC batch updates for versioned data: enabled
17/10/2007 12:22:35 org.hibernate.cfg.SettingsFactory buildSettings
INFO: Scrollable result sets: enabled
17/10/2007 12:22:35 org.hibernate.cfg.SettingsFactory buildSettings
INFO: JDBC3 getGeneratedKeys(): enabled
17/10/2007 12:22:35 org.hibernate.cfg.SettingsFactory buildSettings
INFO: Connection release mode: on_close
17/10/2007 12:22:35 org.hibernate.cfg.SettingsFactory buildSettings
INFO: Maximum outer join fetch depth: 1
17/10/2007 12:22:35 org.hibernate.cfg.SettingsFactory buildSettings
INFO: Default batch fetch size: 1
17/10/2007 12:22:35 org.hibernate.cfg.SettingsFactory buildSettings
INFO: Generate SQL with comments: disabled
17/10/2007 12:22:35 org.hibernate.cfg.SettingsFactory buildSettings
INFO: Order SQL updates by primary key: disabled
17/10/2007 12:22:35 org.hibernate.cfg.SettingsFactory createQueryTranslatorFactory
INFO: Query translator: org.hibernate.hql.ast.ASTQueryTranslatorFactory
17/10/2007 12:22:35 org.hibernate.hql.ast.ASTQueryTranslatorFactory <init>
INFO: Using ASTQueryTranslatorFactory
17/10/2007 12:22:36 org.hibernate.cfg.SettingsFactory buildSettings
INFO: Query language substitutions: {no='N', yes='Y'}
17/10/2007 12:22:36 org.hibernate.cfg.SettingsFactory buildSettings
INFO: JPA-QL strict compliance: disabled
17/10/2007 12:22:36 org.hibernate.cfg.SettingsFactory buildSettings
INFO: Second-level cache: enabled
17/10/2007 12:22:36 org.hibernate.cfg.SettingsFactory buildSettings
INFO: Query cache: disabled
17/10/2007 12:22:36 org.hibernate.cfg.SettingsFactory createCacheProvider
INFO: Cache provider: org.hibernate.cache.HashtableCacheProvider
17/10/2007 12:22:36 org.hibernate.cfg.SettingsFactory buildSettings
INFO: Optimize cache for minimal puts: disabled
17/10/2007 12:22:36 org.hibernate.cfg.SettingsFactory buildSettings
INFO: Cache region prefix: hibernate.test
17/10/2007 12:22:36 org.hibernate.cfg.SettingsFactory buildSettings
INFO: Structured second-level cache entries: disabled
17/10/2007 12:22:36 org.hibernate.cfg.SettingsFactory buildSettings
INFO: Statistics: disabled
17/10/2007 12:22:36 org.hibernate.cfg.SettingsFactory buildSettings
INFO: Deleted entity synthetic identifier rollback: disabled
17/10/2007 12:22:36 org.hibernate.cfg.SettingsFactory buildSettings
INFO: Default entity-mode: pojo
17/10/2007 12:22:36 org.hibernate.cfg.SettingsFactory buildSettings
INFO: Named query checking : enabled
17/10/2007 12:22:36 org.hibernate.impl.SessionFactoryImpl <init>
INFO: building session factory
17/10/2007 12:22:36 org.hibernate.impl.SessionFactoryObjectFactory addInstance
INFO: Not binding factory to JNDI, no JNDI name configured
Exception in thread "main" java.lang.NullPointerException
        at testandospring.HibernateClienteDao.salvar(HibernateClienteDao.java:22)
        at testandospring.Teste.main(Teste.java:37)
Java Result: 1

Quanto as configurações do web.xml, eu tenho que fazer mesmo se não for usar o Spring MVC?

Valeu!

D

Mais uma pergunta:

Os arquivos

conf/applicationContext.xml
conf/applicationContext-DAOs.xml
e conf/applicationContext-Services.xml

Eu devo criar ou já são parte do Spring?

_

Eles são os arquivos de configuração de um projeto aqui. São equivalentes ao seu spring.xml.

Hm, tenho um palpite sobre porquê não funcionou. Normalmente declaramos um transaction manager, que é um interceptor aplicado aos métodos da classe que usa o DAO.

Então, no seu caso, falta fazer o seu DAO entender que deve abrir uma transação antes do método “salvar” ser executado e commita-la após terminar.

Se estiver utilizando Java 5 e annotations, basta seguir este tutorial:
http://www.springframework.org/docs/reference/transaction.html
Mas ao invés de aplicar o interceptor no Service, aplicará diretamente no DAO.

D

Olá LIPE.

Consegui resolver, segui seu padrão de arquivos de configuração e tinha um erro grotesco na minha classe de teste... Olha lá

HibernateClienteDao d =  
                ( HibernateClienteDao) factory.getBean("clienteDao");  
           
        new HibernateClienteDao().salvar( c );

Estava criando um HibernateClienteDao do nada, sem usar o que eu tinha obtido... hehehe

Quanto a transação vou ver isso agora.

Agora mais uma pergunta, fiz um servlet para testar aqui. Como faço para obter o bean configurado no Spring dentro do servlet? No meu teste eu carrego na mão e uso a configuração.

Valeu pela ajuda :D

_

haha olha só.

Servlets? Você não vai MESMO usar servlets, né? :smiley:

O ideal é integrar o Spring com seu WebFramework de preferência, configurando de forma que o Spring crie suas Actions/Commands/Services, automatizando a injeção de dependências.

Se for seguir este caminho, recomendo o DWR.

D

Não, não vou usar servlets, só estou testando.

Deixa eu explicar o que está acontecendo para vc entender.

Tenho uma aplicação para desenvolver que terá que usar o Flex. Para facilitar minha vida na persistência eu vou usar o Hibernate, mas eu não quero ficar abrindo/fechando sessões do Hibernate. Queria deixar isso a cargo do Spring. Só vou usar o Spring única e exclusivamente para dar uma mão com o Hibernate, nada mais.

Por isso queria saber, como obter um bean que foi configurado entendeu?

Abraço!

_

Bom, atualmente estou trabalhando com 2 projetos razoavelmente grandes utilizando Flex (com dataservices), Hibernate e Spring hehe

Para delegar ao Spring a função de criar os Delegates/Services/etc que o Flex chama, basta fazer o seguinte:

  1. Adicionar o seguinte antes do fechamento da tag do arquivo /WEB-INF/flex/services-config.xml

<factories> <factory id="springFactory" class="meu.pacote.SpringFactory"/> </factories>
2. Adicionar o seguinte antes do fechamento da tag do arquivo /WEB-INF/flex/remoting-config.xml

<destination id="usuarioService">
		<properties>
			<factory>springFactory</factory>
			<source>usuarioService</source>
		</properties>
	</destination>

Sendo o ID do bean configurado no seu spring.xml e o atributo “id” o source que será usado no RemoteObject do Flex.

  1. E o código do SpringFactory:
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import flex.messaging.FactoryInstance;
import flex.messaging.FlexFactory;
import flex.messaging.config.ConfigMap;
import flex.messaging.services.ServiceException;

/**
 * *
 * 
 * @author Jeff Vroom
 */
public class SpringFactory implements FlexFactory
{

	private static final String	SOURCE	= "source";

	/**
	 * This method can be used to initialize the factory itself. It is called
	 * with configuration parameters from the factory tag which defines the id
	 * of the factory.
	 */
	public void initialize( String id, ConfigMap configMap )
	{}

	/**
	 * This method is called when we initialize the definition of an instance
	 * which will be looked up by this factory. It should validate that the
	 * properties supplied are valid to define an instance. Any valid properties
	 * used for this configuration must be accessed to avoid warnings about
	 * unused configuration elements. If your factory is only used for
	 * application scoped components, this method can simply return a factory
	 * instance which delegates the creation of the component to the
	 * FactoryInstance's lookup method.
	 */
	public FactoryInstance createFactoryInstance( String id, ConfigMap properties )
	{
		SpringFactoryInstance instance = new SpringFactoryInstance( this, id, properties );
		instance.setSource( properties.getPropertyAsString( SOURCE, instance.getId() ) );
		return instance;
	} // end method createFactoryInstance()

	/**
	 * Returns the instance specified by the source and properties arguments.
	 * For the factory, this may mean constructing a new instance, optionally
	 * registering it in some other name space such as the session or JNDI, and
	 * then returning it or it may mean creating a new instance and returning
	 * it. This method is called for each request to operate on the given item
	 * by the system so it should be relatively efficient.
	 * <p>
	 * If your factory does not support the scope property, it report an error
	 * if scope is supplied in the properties for this instance.
	 */
	public Object lookup( FactoryInstance inst )
	{
		SpringFactoryInstance factoryInstance = ( SpringFactoryInstance ) inst;
		return factoryInstance.lookup();
	}

	static class SpringFactoryInstance extends FactoryInstance
	{
		SpringFactoryInstance( SpringFactory factory, String id, ConfigMap properties )
		{
			super( factory, id, properties );
		}

		@Override
		public String toString()
		{
			return "SpringFactory instance for id=" + getId() + " source=" + getSource() + " scope=" + getScope();
		}

		@Override
		public Object lookup()
		{
			ApplicationContext appContext = WebApplicationContextUtils
					.getWebApplicationContext( flex.messaging.FlexContext.getServletConfig().getServletContext() );
			String beanName = getSource();

			try
			{
				return appContext.getBean( beanName );
			}
			catch( NoSuchBeanDefinitionException nexc )
			{
				ServiceException e = new ServiceException();
				String msg = "Spring service named '" + beanName + "' does not exist.";
				e.setMessage( msg );
				e.setRootCause( nexc );
				e.setDetails( msg );
				e.setCode( "Server.Processing" );
				throw e;
			}
			catch( BeansException bexc )
			{
				ServiceException e = new ServiceException();
				String msg = "Unable to create Spring service named '" + beanName + "' ";
				e.setMessage( msg );
				e.setRootCause( bexc );
				e.setDetails( msg );
				e.setCode( "Server.Processing" );
				throw e;
			}
		}

	}
}

Se você não vai comprar o servidor do Flex, pode usar o Granite (google), que faz as mesma coisa, mas sem o push de dados.

Mas, respondendo sua dúvida sobre Servlets, não sei como configurar para o Spring criá-los, de forma que injetasse as dependências.

D

Ola LIPE.

Obrigado pelas respostas.

Então, não usaremos o Flex Data Services, pois ainda estamos engatinhando na tecnologia, e infelizmente não temos verba para treinamento, é tudo aprendido na raça infelizmente.

O que eu precisava eu encontrei dentro da implementação da SpringFactory que você postou, eu não queria criar servlets e injetar dependências nos mesmos, queria simplesmente pegar um bean que foi criado. Eu quase cheguei no que vc postou, passei raspando :smiley:

Agora a última pergunta, prometo :smiley:

O Spring me garante o fechamento de sessão do hibernate né?

Abraço!

_

Se você configurar o TransactionInterceptor direitinho, sim.

Quanto ao DataServices, não tem muito que aprender. Configurando o services-config.xml e remoting-config.xml, no flex basta fazer algo como:

protected var service:RemoteObject  = new RemoteObject( "usuarioService" );
service.source = "usuarioService";
service.addEventListener(InvokeEvent.INVOKE, invoke);
service.addEventListener(ResultEvent.RESULT, result);
service.addEventListener(FaultEvent.FAULT, fault);

service.savePessoa( pessoa );
D

Valeu pelas dicas LIPE!

Abraço!

B

E ai caras tudo beleza.

Eu estou a desenvolver uma aplicacao web e to querendo usar o spring. Ja encontrei alguns tutoriais que explicam o que devo configurar para comecar, mas eu nao entendo por exemplo para que server o listener e o filtre.

Sera que podem explicar-me ou indicar um tutorial onde expliquem isso?

Obrigado.

H

Quais são as bibliotecas necessárias para rodar utilizar o spring?

já tenho todos os arquivos de configuração só não sei quais são as biblioteca atuais, que são necessárias para rodar o spring em um sistema web

Tenho o marven instalado no eclipse 3.7, mais ele é só um complemento para gerencias as dependencias.

H

Bem baixei o arquivo spring-framework-3.1.0.RELEASE-with-docs, segundo o site é a ultima versão do spring. Porém quando descompactei notei os seguintes arquivos

  • dist
  • docs
  • projects

dentro de cada pasta desta há diversas bibliotecas, quais devo utilizar?

att.

H

Algumas bibliotecas mudam do spring 2.XX para o 3.XX. Por isso fique atento na migração segui um tutorial interessante.

http://www.roseindia.net/spring/spring3/spring-3-hello-world.shtml

att.

Criado 16 de outubro de 2007
Ultima resposta 29 de jan. de 2012
Respostas 17
Participantes 4