Статьи

EJB 3.0 и Spring 2.5

Почему разработчики из этих двух сообществ не любят смотреть в глаза? Я использовал Spring как с самого начала, так и EJB с 2001 года. Как и все остальные, я просто боялся огромного количества XML, которое мы должны были написать для них обоих; конфигурационные файлы в Spring и дескрипторы развертывания в EJB 2.x. Тем не менее, Java 5 пришла нам на помощь, и теперь аннотации в большинстве случаев заменяют XML-файлы. Но после использования этих двух последних версий Spring 2.5 и EJB 3.0 я думаю, что они дополняют друг друга, а не конкурируют друг с другом. Есть определенные функции, которые являются мощными в Spring, и такое же количество функций, мощных на стороне EJB.

Многие разработчики не понимают, что Spring — это популярная нестандартная среда, созданная Spring Source, а EJB 3.0 — это спецификация, поддерживаемая основными поставщиками JEE. Есть несколько разработчиков, с которыми я работал ранее, предпочитают использовать стандартную спецификацию, они выбрали EJB2.x / и сейчас переходят на EJB 3.0. Однако ничто не мешает вам использовать Spring вместе с EJB, не так ли? Жалоба, которую я слышал много раз: «Мы не можем использовать нестандартные фреймворки». Те же разработчики, которые жалуются на то, что Spring является нестандартным, используют доморощенные фреймворки, которые было и будет всегда так трудно даже расшифровать. Как можно это будет спецификация, когда пара разработчиков пишут несколько тысяч строк кода?

Также, недавняя статья, опубликованная здесь в Javalobby Адамом Бьеномпоказал тенденцию движения к EJB 3.0, верно? В любом случае, в этой статье мы увидим, как, добавив несколько строк в ваш конфигурационный файл Spring, вы можете легко использовать компоненты EJB 3.0 в вашем приложении Spring.

Возвращаясь к нашей статье о EJB 3.0 и Spring 2.5 , мы увидим, как легко и просто получить доступ к компонентам EJB 3.0 в Spring с помощью мощного механизма внедрения зависимостей для внедрения экземпляра нашего компонента сеанса Customer. Этот сессионный компонент Customer , в свою очередь, использует Entity Manager для операций CRUD над объектом Customer .

Вот подробные шаги:

Шаг 1: Создайте простой объект JPA.

API сохранения состояния Java (JPA) , определяется как часть спецификации Java EE 5. Создание сущностей с использованием JPA так же просто, как создание POJO с несколькими аннотациями, как показано ниже:

package com.ejb.domain;

import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

/**
*
* @author meerasubbarao
*/
@Entity
@Table(name = "CUSTOMER", catalog = "", schema = "ADMIN")
public class Customer implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Column(name = "CUSTOMER_ID")
private Long customerId;
@Column(name = "FIRST_NAME")
private String firstName;
@Column(name = "LAST_NAME")
private String lastName;
@Column(name = "MIDDLE_NAME")
private String middleName;
@Column(name = "EMAIL_ID")
private String emailId;

public Customer() {
}

public Customer(Long customerId) {
this.customerId = customerId;
}

public Long getCustomerId() {
return customerId;
}

public void setCustomerId(Long customerId) {
this.customerId = customerId;
}

public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public String getMiddleName() {
return middleName;
}

public void setMiddleName(String middleName) {
this.middleName = middleName;
}

public String getEmailId() {
return emailId;
}

public void setEmailId(String emailId) {
this.emailId = emailId;
}


}

Шаг 2. Создайте компонент EJB 3.0 Session.

Этот сессионный компонент использует Entity Manager для операций Create Read Update Delete (CRUD) для объекта Customer, который мы создали на шаге 1. Операции CRUD также публикуются в виде веб-методов путем добавления нескольких основных аннотаций.

Интерфейс:

 
package com.ejb.service;

import com.ejb.domain.Customer;
import java.util.Collection;
import javax.ejb.Remote;

/**
*
* @author meerasubbarao
*/
@Remote
public interface CustomerService {

Customer create(Customer info);

Customer update(Customer info);

void remove(Long customerId);

Collection<Customer> findAll();

Customer[] findAllAsArray();

Customer findByPrimaryKey(Long customerId);
}

Класс реализации:

package com.ejb.service;

import com.ejb.domain.Customer;
import java.util.Collection;
import javax.ejb.Stateless;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.jws.WebMethod;

/**
*
* @author meerasubbarao
*/
@WebService(name = "CustomerService", serviceName = "CustomerService", targetNamespace = "urn:CustomerService")
@SOAPBinding(style = SOAPBinding.Style.RPC)
@Stateless(name = "CustomerService")
public class CustomerServiceImpl implements CustomerService {

@PersistenceContext
private EntityManager manager;

@WebMethod
public Customer create(Customer info) {
this.manager.persist(info);
return info;
}

@WebMethod
public Customer update(Customer info) {
return this.manager.merge(info);
}

@WebMethod
public void remove(Long customerId) {
this.manager.remove(this.manager.getReference(Customer.class, customerId));
}

public Collection<Customer> findAll() {
Query query = this.manager.createQuery("SELECT c FROM Customer c");
return query.getResultList();
}

@WebMethod
public Customer[] findAllAsArray() {
Collection<Customer> collection = findAll();
return (Customer[]) collection.toArray(new Customer[collection.size()]);
}

@WebMethod
public Customer findByPrimaryKey(Long customerId) {
return (Customer) this.manager.find(Customer.class, customerId);
}


}

Шаг 3. Компиляция, упаковка и развертывание на сервере приложений.

В классе Entity или в компоненте Session нет специфических для сервера аннотаций. Упакуйте класс сущности, интерфейс сессионного компонента, класс реализации вместе с файлом persistence.xml в файл JAR. Поскольку я развертываю это приложение на GlassFish, я использую поставщика постоянства по умолчанию, который называется TopLink. Запустите сервер приложений и разверните на нем этот JAR-файл. Содержимое файла persistence.xml показано ниже:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="SpringAndEJBPU" transaction-type="JTA">
<provider>oracle.toplink.essentials.PersistenceProvider</provider>
<jta-data-source>spring-ejb</jta-data-source>
<properties>
<property name="toplink.ddl-generation" value="drop-and-create-tables"/>
</properties>
</persistence-unit>
</persistence>

После развертывания приложения обязательно проверьте имя JNDI вашего сессионного компонента . В GlassFish нажмите на кнопку панели инструментов JNDI Browsing , чтобы просмотреть имена JNDI.

 

Шаг 4: Тестирование сессионных компонентов без сохранения состояния.

Поскольку мои сессионные компоненты публикуются в виде веб-служб, я могу легко протестировать их с помощью либо тестовой страницы, предоставляемой сервером приложений GlassFish, либо с помощью SoapUI и убедиться, что моя сущность Customer может быть сохранена с помощью сессионного компонента CustomerService. Я использую тестовую страницу по умолчанию, предоставленную Glass Fish для веб-сервисов:

Шаг 5: Создайте Spring Bean.

Здесь я определяю простой интерфейс CustomerManager и класс реализации; просто чтобы показать, как все устроено, используя Spring.

package com.spring.service;

import com.ejb.domain.Customer;

/**
*
* @author meerasubbarao
*/
public interface CustomerManager {

public void addCustomer(Customer customer);
public void removeCustomer(Long customerId);
public Customer[] listCustomers();


}
package com.spring.service;

import com.ejb.domain.Customer;
import com.ejb.service.CustomerService;

/**
*
* @author meerasubbarao
*/
public class CustomerManagerImpl implements CustomerManager {

CustomerService customerService;

public void setCustomerService(CustomerService customerService) {
this.customerService = customerService;
}

public void removeCustomer(Long customerId) {
customerService.remove(customerId);
}

public Customer[] listCustomers() {
return customerService.findAllAsArray();
}

public void addCustomer(Customer customer) {
customerService.create(customer);
}
}

Шаг 6: Внедрение EJB 3.0 Session bean в наши Spring Bean.

Как видно из вышеизложенного, я использую метод установки для внедрения экземпляра службы поддержки клиентов и, в свою очередь, вызываю метод для сессионного компонента без сохранения состояния. Как мы вводим EJB в бин Spring? Это довольно просто, как показано ниже в конфигурационном файле Spring:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd">
<jee:jndi-lookup id="customerService" jndi-name="com.ejb.service.CustomerService">
</jee:jndi-lookup>
<bean id="manageCustomer"
class="com.spring.service.CustomerManagerImpl">
<property name="customerService" ref="customerService" />
</bean>
</beans>

Наиболее важным аспектом здесь является подключение EJB в конфигурации Spring с использованием элемента <jee: jndi-lookup> в схеме jee .

<jee:jndi-lookup id="customerService" jndi-name="com.ejb.service.CustomerService">
</jee:jndi-lookup>

Затем нам нужно связать это с нашим bean-компонентом Spring, как показано ниже:

    <bean id="manageCustomer"
class="com.spring.service.CustomerManagerImpl">
<property name="customerService" ref="customerService" />
</bean>

Шаг 7: Тест

Откуда мы знаем, что это работает. Давайте создадим простой класс и протестируем.

package com.spring.client;

import com.ejb.domain.Customer;
import com.spring.service.CustomerManager;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringAndEJBMain {

public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("SpringXMLConfig.xml");

CustomerManager service = (CustomerManager) context.getBean("manageCustomer");
Customer customer = new Customer();
customer.setFirstName("Meera");
customer.setLastName("Subbarao");
customer.setMiddleName("B");
customer.setEmailId("[email protected]");
customer.setCustomerId(new Long(1));

service.addCustomer(customer);
for (Customer cust : service.listCustomers()) {
System.out.println(cust.getFirstName());
System.out.println(cust.getLastName());
System.out.println(cust.getMiddleName());
System.out.println(cust.getEmailId());

}
service.removeCustomer(new Long(1));

}
}

А вот пример вывода из моей IDE:

 

Мы можем вернуться на нашу тестовую страницу веб-сервисов GlassFish и протестировать метод findAll. У него должно быть два объекта.

В этой статье мы увидели, как быстро и легко создавать сущности JPA, сохраняя их с помощью Entity Manager из нашего сессионного компонента. Мы также увидели, как легко публиковать веб-сервисы, добавив несколько аннотаций к нашим сессионным компонентам. Далее мы увидели, как создать простой Spring-компонент, внедрить наш сессионный компонент и, наконец, вызвать методы этого сессионного компонента из нашего приложения Spring.

Spring, на мой взгляд, не является заменой EJB 3.0, вы можете смешивать и сочетать компоненты EJB 3.0 и Spring 2.5, чтобы получить лучшее из обоих.