Познакомьтесь с Java EE 5

Значительные улучшения обеспечивают более быструю, удобную и простую разработку корпоративных приложений

Краткий обзор новой спецификации Java™ EE 5, ее многочисленных существенных расширений функциональности и того, что это значит для Ваших WebSphere®-приложений.

Роланд Барсиа, дипломированный специалист по IT, IBM

Роланд Барсиа - дипломированный специалист по IT для IBM Software Services для WebSphere в районе New York/New Jersey Metro. Он является соавтором IBM WebSphere: Развертка и дополнительные конфигурации



07.09.2007

Вступление

Взгляд на историю спецификации Java Platform, Enterprise Edition (Java EE) показывает, что каждый значительный пересмотр спецификации обуславливается какой-либо ведущей темой. К примеру, в первом релизе J2EE™ 1.2 произошло первое объединение отдельных спецификаций, в J2EE 1.4 фокусом стали Web-сервисы. На Рис.1 представлена хронологическая сводка Java EE, на которой указаны важнейшие функциональные возможности каждой версии, а также некоторые существенные внешние факторы, которые воздействовали на их формирование.

Рис. 1. История Java EE
Рис. 1. История Java EE

Как и в большинстве ранних версий новых технологий, в предыдущих версиях спецификации Java EE обнаружился ряд «подводных камней», в том числе:

  • Сложность программирования бизнес-логики.
  • Сложность и производительность модели программирования персистентности.
  • Соединение логики и уровня представления.
  • Типы, сложность, модель документа, расширения и производительность Web-сервисов.
  • Разработка приложений командой программистов.
  • Долгий цикл «редактирование-компилирование-отладка».

Неудивительно, что темой спецификации Java EE 5 стало упрощение. Для достижения этой цели процесс разработки был улучшен в следующих областях:

  • Упрощенное программирование бизнес-логики.
  • Упрощенное тестирование и управление зависимостями.
  • Упрощенная объектно-реляционная модель персистентности.
  • Расширенная модель программирования Web-сервисов.

Большинство обновлений в Java EE 5 было обусловлено появлением новых технологий как в коммерческой области, так и в области ПО с открытым исходным кодом, таких как Hibernate, Spring, Service Data Object (SDO) и другие. Кроме того, имеется также ряд ожидаемых обновлений на уровне спецификаций с незначительными улучшениями функциональности.

Чтобы подготовить Вас к работе с Java EE 5, в этой статье освещаются некоторые важнейшие особенности новой спецификации, такие как EJB 3.0, Java Persistence Architecture (JPA), Web-сервисы, JAX-WS и другие, а затем дается краткий обзор того, что мы можем ожидать от Java EE 6.


EJB 3.0

Среди всех технологических расширений Java EE 5 несомненно, самым важным является спецификация JavaBean™ (EJB) 3.0, значительные косметические изменения которой намного упрощают разработку. Спецификация EJB 3.0 разбита на три подраздела:

  • Упрощенный API EJB 3.0: Определяет новый упрощенный API, который используется для программирования EJB-компонентов, особенно session beans и message-driven beans.

  • Основные Контракты и Требования: Определяют EJB-контракты между bean и EJB-контейнером.

  • Java Persistence Architecture API: Определяет новую модель entity bean для персистентности.

Далее в статье будут рассмотрены изменения EJB 3.0 и JPA API.

Упрощение EJB 3.0

POJO (Plain Old Java Objects) – популярный в последнее время термин, которым обозначают код, написанный как простые Java-классы. Поскольку программы EJB 2.x требуют расширения конкретных классов, предоставления нескольких интерфейсов и написания установочных дескрипторов, они рассматриваются как «перегруженные» Java-объекты, которые более не являются простыми – для их запуска и исполнения необходим J2EE-контейнер. В EJB 3.0 ситуация изменяется:

  • EJB-компоненты более не требуют наличия домашних интерфейсов. Также от EJB компонентов более не требуется предоставление различных интерфейсов либо расширение каких-либо EJB-специфичных классов.

  • Аннотации J2SE 5.0 теперь значительно упрощают для развертывание EJB 3.0 компонентов. Указывая специальные аннотации, разработчики могут создавать POJO классы, которые будут являться EJB компонентами, как альтернатива XML.

  • EJB 3.0 вводит понятие бизнес-интерфейса вместо отдельных удаленного и локального интерфейсов. Пример приведен ниже:

    Листинг 1
    public interface Stock 
    {public double getQuote(String symbol);}

    Ваш bean-класс может реализовывать такой интерфейс:

    Листинг 2
    @Stateless public class StockBean implements Stock
    	public double getQuote(String symbol)
    	{
    		return 100.33;
    	}
    }

    Аннотация @Stateless в приведенном выше примере означает, что этот класс теперь является stateless session bean и для его вызова используется наш бизнес-интерфейс. Stateless session bean также можно написать, не реализуя какой-либо специальный интерфейс; его сгенерирует для вас контейнер:

    Листинг 3
    @Stateless public class StockBean
    	public double getQuote(String symbol)
    	{
    		return 100.33;
    	}
    }

    По умолчанию в бизнес-интерфейс включены все public-методы, за исключением случаев, когда методы аннотированы особым образом. Например, если Вы определяете хотя бы один метод с аннотацией @BusinessMethod, то в бизнес-интерфейс будут включены только те методы, которые обозначены @BusinessMethod:

    Листинг 4
    @Stateless public class StockBean
    	@BusinessMethod public double getQuote(String symbol)
    	{
    		return 100.33;
    	}
    }

    Теперь, когда Вы имеете один интерфейс, как определить удаленность или локальность метода? Конечно, Вы можете использовать аннотацию:

    Листинг 5
    @Stateless public class StockBean
    	@Remote public double getQuote(String symbol)
    	{
    		return 100.33;
    	}
    }

    Вы можете аннотировать либо бизнес-интерфейс, либо сам бин-класс. Аннотирование бин-класса полезно, если Вы решили генерировать бизнес-интерфейс.

Обновления спецификации EJB 3.0 включают:

  1. Сервисы контейнеров
  2. Обратные вызовы
  3. Интерсепторы (ловушки)
  4. Внесение зависимостей (отношений)
  1. Сервисы контейнеров

    EJB-компоненты популярны из-за неявной поддержки управления и безопасности транзакций. Спецификация EJB 3.0 использует аннотации (в дополнение к XML) для реализации сервисов контейнеров. Вот пример того, как следует определять атрибут транзакции для stateless session bean:

    Листинг 6
    @Stateless public class StockBean
    {
    
    @TransactionAttribute(TransactionAttributeType.REQUIRESNEW)
    	public double getQuote(String symbol)
    	{
    		return 100.33;
    	}
    }

    Эта аннотация означает, что метод будет запущен в новой транзакции. Конкретный синтаксис и семантика различных аннотаций приведены в спецификации, однако все функциональности, касающиеся транзакций и безопасности, имеют аннотации. Сервисы контейнеров также могут применяться с помощью XML-дескрипторов развертывания, которые также позволяют переопределять аннотации, что дает некоторую гибкость при развертывании.

  2. Обратные вызовы (Callbacks)

    Теперь перейдем к обратным вызовам. До версии EJB 3.0 методы обратных вызовов, например, ejbCreate(), приходилось реализовывать на уровне класса бина. Классы бина должны были реализовывать все методы, вне зависимости от того, использовали они их или нет. В большинстве случаев эти реализации методов были пусты. Теперь обратные вызовы также реализуются с помощью аннотаций, используя либо методы обратных вызовов, либо классы приемника (listener) обратных вызовов. Вот пример кода для ответа на обратный вызов, использующий методы обратного вызова.

    Листинг 7
    @Stateless public class StockBean implements Stock
    	public double getQuote(String symbol)
    	{
    		return 100.33;
    	}
    
    	@PostConstruct initializeCache()
    	{
    	}
    }

    Строки, приведенные выше, позволяет Вам реализовать код уже после того, как экземпляр бина создан. Если Вы хотите использовать приемник обратных вызовов, то можно создать класс такого приемника:

    Листинг 8
    public class MyCallbackListener
    {
    	@PrePassivate public clearCache(Object obj)
    	{
    		Stock stock = (Stock) obj;
    		//perform logic
    	}
    }

    Класс обратного вызова, который не входит в бин-класс, должен принимать параметр java.lang.Object. В этом случае контейнер передаст экземпляр бина. Класс бина добавляет класс приемника обратных вызовов, используя специальную аннотацию обратных вызовов на уровне класса бина:

    Листинг 9
    @CallbackListener MyCallbackListener
    @Stateless public class StockBean implements Stock
    	public double getQuote(String symbol)
    	{
    		return 100.33;
    	}
    }

    Обратные вызовы очень удобны тем, что включение их в Ваш код является условным, в отличие от тех случаев, когда Вы реализуете интерфейсы.

  3. Интерсепторы (ловушки)

    Отличной новинкой спецификации EJB является использование ловушек. Одной из функциональностей, отсутствующей в EJB компонентах, была возможность выполнять аспектно-ориентированную разработку (AOP) для таких вещей, как пре- и пост-процессинг и cross-cutting concerns, аналогично тому, как работают сервлет-фильтры для сервлетов. Теперь Вы можете разработать класс ловушки и применить его к бину. Вот пример ловушки, которая следит за вызовами класса StockBean:

    Листинг 10
    public class StockRequestAudit {
    	@AroundInvoke
    	public Object auditStockOperation(InvocationContext inv) throws
    	Exception {
    		try {
    			Object result = inv.proceed();
    			Auditor.audit(inv.getMethod().getName(), inv.getParameters[0]);
    			return result;
    		} catch (Exception ex) {
    			Auditor.auditFailure(ex);
    			throw ex;
    		}
    	}
    }

    Ловушка, приведенная выше, перехватывает вызовы к целевым EJB методам, а затем вызывает метод proceed() для InvocationContext. Это позволяет такому вызову пройти к текущему методу EJB, который и был вызван. После того как целевой метод EJB выполняется, он на основании метаданных в InvocationTarget получает имя метода и параметры целевого компонента EJB, который был вызван. Затем ловушка может быть применена к бин-классу:

    Листинг 11
    @Stateless @Interceptors({StockRequestAudit})
    public class StockBean implements Stock
    	public double getQuote(String symbol)
    	{
    		return 100.33;
    	}
    }

    Также Вы можете разрабатывать методы ловушки, реализованные внутри бин-класса, и определять несколько ловушек. В этом случае порядок их вызова определяется порядком, в котором они определены в бин-классе. Ловушки также можно применять, используя XML вне бина, что является более предпочтительным в случае AOP, так как позволяет “прозрачно” применять cross cutting concerns к бинам.

  4. Внесение зависимостей (отношений)

    Зависимости кода EJB (например, от источников данных) и способ, с помощью которого компоненты EJB вызываются клиентами, принадлежат к числу факторов, которые затрудняют тестирование EJB при разработке. В качестве механизма, позволяющего облегчить эту ситуацию, спецификация EJB 3.0 представляет внесение зависимостей. Вместо использования JNDI lookup в EJB можно определить ссылку на ресурс путем встраивания кода. Вот пример EJB-бина, которому нужно вызвать другой EJB компонент и использовать источник данных для выполнения JDBC-задач:

    Листинг 12
    @Stateless public class StockBean implements Stock
    {
    @EJB(name="MarketBean", businessInterface="Market")
    Market market;
    
    @Resource(name="StockDB, resourceType="javax.sql.DataSource")
    DataSource stockDS
    
    	public double getQuote(String symbol)
    	{
    		Connection con = stockDS.getConnection();
    		//DO JDBC work
    
    			return market.getCurrentPrice(symbol);
    	}
    }

    Зависимости могут вноситься многими способами, например, с помощью setter-метода или переменной класса. Для более подробного ознакомления обратитесь к спецификации.

Java Persistence Architecture (JPA)

Спецификация для персистентности EJB сильно изменилась. Эта спецификация, известная, как Container Managed Persistence (CMP), не определяла связывающего слоя и управлялась контейнером. Таким образом, задача связывания перекладывалась на плечи вендора. Под влиянием ряда коммерческих и открытых продуктов и технологий, таких как Hibernate, Java Data Objects (JDO) и TopLink, EJB 3.0 вводит новый стиль персистентности, основанный на POJO. Его особенности:

  • Основывается на проверенных шаблонах.
  • Упрощает шаблоны доступа JDBC.
  • Может быть интегрирован с Web-сервисами.
  • Не затрагивает контейнер, что позволяет использовать JPA в средах Java EE и Java SE.
  • Использует стандартизированные объектно-реляционные метаданные.
  • Поддерживает модели разработки top-down, meet-in-the-middle и bottom-up.
  • Поддерживает отсоединенные и соединенные состояния объекта. Таким образом, ликвидируется потребность в отдельных Data Transfer Objects. Пример представлен на Рис.2.
Рис. 2. Поддержка состояний объекта
Рис. 2. Поддержка состояний объекта

Обновления JPA API включают:

  1. Типы: сущности и таблицы
  2. Экземпляры: Java-объекты
  3. Атрибуты: свойства Java и аннотации столбцов
  4. Зависимые объекты: встраиваемые Java-объекты
  5. Производные атрибуты: временные аннотации
  6. Ключевые атрибуты: аннотированные поля и ключевые классы
  7. Связи: аннотации и связывание столбцов
  8. Ограничения: аннотации и базы данных
  9. Наследование: аннотации -- одиночная таблица, связанная таблица и таблица для класса
  1. Типы: сущности и таблицы

    Типами в JPA являются сущности (более не носящие название entity beans), которые могут быть связаны с таблицами. Основным механизмом для связывания является аннотирование класса объекта. Ниже приведен пример связывания Java-объекта Customer и таблицы CUSTOMER:

    Листинг 13
    @Entity
    @Table(name="CUSTOMER")
    public class Customer implements Serializable {
    ...

    Класс аннотируется как сущность и с помощью аннотации ассоциируется с покупателем. В качестве альтернативы или механизма переопределения может использоваться дескриптор развертывания.

  2. Экземпляры: Java-объекты

    Приложения взаимодействуют с Java-объектами во время выполнения. Используя специальный объект, который называется entity manager, приложения могут опрашивать объекты или делать их персистентными. Entity manager внедряется в приложение с использованием внесения зависимостей в рамках EJB-контейнера (либо он может быть найден при помощи EntityManagerFactory в среде Java SE). Вот пример:

    Листинг 14
    @PersistenceContext (unitName="db2")
    private EntityManager em;

    Приложения могут извлекать объекты из entity manager и передавать их в entity manager. Вот пример приложения, использующего entity manager для нахождения объекта по его основному ключу:

    Листинг 15
    Customer customer = (Customer)em.find(Customer.class,customerId);

    Вот еще один пример - создание Java-объекта и сохранение его в базе данных путем его передачи в entity manager:

    Листинг 16
    CustomerOrder newOrder = new CustomerOrder();
    newOrder.setStatus("OPEN");
    newOrder.setTotal(new Integer(0));
    newOrder.setCustomerId(customerId);
    em.persist(newOrder);
  3. Атрибуты: свойства Java и аннотации к столбцам

    Атрибуты – это свойства Java в классе. Свойства Java могут быть связаны со столбцами в базе данных через аннотацию @column. Существуют две формы связывания свойств: Field и Property (по умолчанию):

    Листинг 17
    @Entity(access=FIELD)
    @Table(name="PRODUCT")
    public class Product implements Serializable {
    
    	@Id
    	@Column(name="SKU")
    	Integer sku;
    
    	@Column(name="DESC")
    	String description;
    
    	@Column(name="PRICE")
    	Integer cost;
  4. Зависимые объекты: встраиваемые Java объекты

    JPA имеет поддержку зависимых объектов. Вы можете создавать специальный объект, который называется встраиваемым. Он определяется аннотированием класса как @Embeddable:

    Листинг 18
    @Embeddable
    public class CustomerAddress {
    private int streetAddress;
    private String city;
    private String state;
    private String country;
    ...
    }

    Затем Вы можете определить этот объект как поле в классе объекта:

    Листинг 19
    @Entity
    @Table(name="CUSTOMER")
    public class Customer {
    	private String name;
    	private CustomerAddress ca;
    
    @Embedded
    @AttributeOverrides({
    @AttributeOverride(name="streetAddress", column=@Column("
    STRT_ADD")),
    @AttributeOverride(name="city", column=@Column("CITY"))
    ... //more
    })
    	public CustomerAddress getCustomerAddress()
    {
    
    ...
    }

    Используя такую специальную перегрузку атрибута, Вы можете связать поля встраиваемого класса в рамках объекта. Альтернативный подход состоит в непосредственном связывании столбцов во встраиваемом классе.

  5. Производные атрибуты: временные аннотации

    По умолчанию все поля в JPA являются постоянными, однако вы можете пометить поле как временное. Это позволит порождать любое поле программно. Ниже показано порождение поля с помощью запроса:

    Листинг 20
    @Transient
    public Integer getTotal() {
    
    	Query totalLineItems = em.createNamedQuery("getOrderTotal");
    	totalLineItems.setParameter("orderId",orderId);
    	Integer result = (Integer)totalLineItems.getSingleResult();
    	return result;
    }
  6. Ключевые атрибуты: аннотированные поля и ключевые классы

    JPA поддерживает несколько разновидностей первичных ключей, а также различные способы генерации ключа. В простейшем варианте Вы можете аннотировать поле Вашего объекта как первичный ключ при помощи аннотации @Id:

    Листинг 21
    @Entity
    @Table(name="CUSTOMER")
    public class Customer implements Serializable {
    
    	private Integer id;
    	private String name;
    	private CustomerOrder currentOrder;
    	
    		
    	@Id
    	@Column(name="CUST_ID")
    	public Integer getId() {
    		return id;
    	}
    	public void setId(Integer id) {
    		this.id = id;
    	}
    ...

    Также можно создать класс первичного ключа для сущностей, имеющих составные ключи:

    Листинг 22
    public class LineItemId implements Serializable {
    
    	private Integer orderId;
    	private Integer productId;
    	public LineItemId() {
    		super();
    		// TODO Auto-generated constructor stub
    	}
    	@Column(name="ORDER_ID")
    	public Integer getOrderId() {
    		return orderId;
    	}
    	public void setOrderId(Integer orderId) {
    		this.orderId = orderId;
    	}
    	
    	@Column(name="PRODUCT_ID")
    	public Integer getProductId() {
    		return productId;
    	}
    	public void setProductId(Integer productId) {
    		this.productId = productId;
    	}
    	public boolean equals(Object arg0) {
    		if (arg0 == this) return true;
    		    if (!(arg0 instanceof LineItemId)) return false;
    			LineItemId other = (LineItemId)arg0;
    			if(other.getOrderId().equals(orderId) &&
    				other.getProductId().equals(productId))
    			{
    				return true;
    			}
    			return false;
    		
    	}
    	public int hashCode() {
    		return orderId + productId.hashCode();
    	}
    
    }

    Затем можно определить композитный ключ для Вашей сущности, используя аннотацию @IdClass:

    Листинг 23
    @Entity
    @Table(name="LINEITEM")
    @IdClass(LineItemId.class)
    public class LineItem implements Serializable {

    Ваш класс сущности должен иметь поля, совпадающие с полями класса, либо он может включать ключ как встраиваемый:

    Листинг 24
    @Entity
    @Table(name="LINEITEM")
    @IdClass(LineItemId.class)
    public class LineItem implements Serializable {
    	private LineItemId lineItemId;
    
    	@EmbeddedId
    public LineItemId getLineItemId()
    	{
    		return lineItemId;
    	}
    
    ...

    Другим значительным расширением функциональности является поддержка генерации первичных ключей. С помощью атрибута generate аннотации @Id можно реализовать несколько иную стратегию. Например, можно делегировать генерацию первичного ключа в столбец идентификаторов DB2, как показано здесь:

    Листинг 25
    @Id(generate=GeneratorType.IDENTITY)
    @Column(name="ORDER_ID")
    public Integer getOrderId() {
    	return orderId;
    }
    public void setOrderId(Integer orderId) {
    	this.orderId = orderId;
    }

    Другие поддерживаемые механизмы включают генерацию последовательностей и таблиц.

  7. Связи: Аннотации и связывание столбцов

    JPA имеет мощную поддержку связей между сущностями. JPA поддерживает такие типы связей, как один-к-одному, один-ко-многим, многие-к-одному и многие-ко-многим. В JPA такие связи не являются двунаправленными, как в EJB 2.x. Вместо этого, объекты объявляют другие сущности своими членами, а добавляемые аннотации определяют связи. Связь можно сделать двунаправленной, используя специальный атрибут. Ниже приводится пример класса CustomerOrder с двумя разными связями:

    Листинг 26

    Кликните, чтобы увидеть код

    Листинг 26

    @Entity
    @Table(name="CUSTOMER")
    public class Customer implements Serializable {
    
    	
    	private Integer id;
    	private String name;
    	private CustomerOrder currentOrder;
    	
    		
    	@Id
    	@Column(name="CUST_ID")
    	public Integer getId() {
    		return id;
    	}
    	public void setId(Integer id) {
    		this.id = id;
    	}
    	
    	@Column(name="NAME")
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    	
      @OneToOne(cascade=CascadeType.ALL , fetch=FetchType.EAGER )  @JoinColumn(name="OPEN_ORDER_ID",referencedColumnName="ORDER_ID")  public CustomerOrder getCurrentOrder() {     return currentOrder;  }  public void setCurrentOrder(CustomerOrder currentOrder) {     this.currentOrder = currentOrder;  }
    
    }

    В этой связи определяется отношение один-к-одному между Customer и CustomerOrder при помощи аннотирования свойства CustomerOrder в классе Customer. Также определяется информация JoinColumn. Атрибут name определяет внешний ключ для таблицы, с которой связан класс Customer, а столбец referenced определяет первичный ключ, с которым связана таблица CustomerOrder. Ограничения на связь задаются как атрибут аннотации @OneToOne. Класс CustomerOrder приведен ниже. Он также имеет свойство Cutomer, однако объект CustomerOrder имеет отношения типа один-ко-многим с Customer. Это сделано потому, что Customer может иметь только один текущий заказ. На самом деле заказчик может иметь несколько заказов, что и отражено в CustomerOrder. Однако используемый здесь атрибут mappedBy указывает, что CustomerOrder привязан к классу Customer. Этот класс приведен ниже:

    Листинг 27
    public class CustomerOrder implements Serializable {
    	private Integer orderId;
    	private String status;
    	private Integer total;
    	private Integer customerId;
    	private Collection<LineItem> lineItems;
    	private Customer customer;
    	
    	@Column(name="CUSTOMER_ID")
    	public Integer getCustomerId() {
    		return customerId;
    	}
    	public void setCustomerId(Integer customerId) {
    		this.customerId = customerId;
    	}
    	
    	@Id(generate=GeneratorType.IDENTITY)
    	@Column(name="ORDER_ID")
    	public Integer getOrderId() {
    		return orderId;
    	}
    	public void setOrderId(Integer orderId) {
    		this.orderId = orderId;
    	}
    	@Column(name="STATUS")
    	public String getStatus() {
    		return status;
    	}
    	public void setStatus(String status) {
    		this.status = status;
    	}
    	@Column(name="TOTAL")
    	public Integer getTotal() {
    		return total;
    	}
    	public void setTotal(Integer total) {
    		this.total = total;
    	}
    Листинг 27.1

    Кликните, чтобы увидеть код

    Листинг 27.1

      @ManyToOne(fetch=FetchType.EAGER,optional=false)  @JoinColumn(name="CUSTOMER_ID",     referencedColumnName="CUST_ID",insertable=false,updatable=false,     nullable=false,unique=true)   public Customer getCustomer() {     return customer;  }  public void setCustomer(Customer customer) {     this.customer = customer;  }  @OneToMany(mappedBy="customerOrder", cascade=CascadeType.ALL ,      fetch=FetchType.EAGER)  public Collection<LineItem> getLineItems() {     return lineItems;  }  public void setLineItems(Collection<LineItem> lineItems) {     this.lineItems = lineItems;}
    
    }

    Другая связь в CustomerOrder содержит коллекцию объектов LineItem. Это связь вида один-ко-многим. Заметьте, что JRE 5 определяет использование групп, определяя тип коллекции. Здесь снова используется специальный атрибут mappedBy, который задает двунаправленное отношение, отображаемое другой стороной отношения.

    Листинг 28

    Кликните, чтобы увидеть код

    Листинг 28

    @Entity
    @Table(name="LINEITEM")
    @IdClass(LineItemId.class)
    public class LineItem implements Serializable {
    	
    	private Product product;
    	private Integer orderId;
    	private Integer productId;
    	private Integer quantity;
    	private Integer total;
    	private CustomerOrder customerOrder;
    	
    	@Column(name="QUANTITY")
    	public Integer getQuantity() {
    		return quantity;
    	}
    	public void setQuantity(Integer quantity) {
    		this.quantity = quantity;
    	}
    	
    	@Column(name="AMOUNT")
    	public Integer getTotal() {
    		return total;
    	}
    	public void setTotal(Integer total) {
    		this.total = total;
    	}
    	
      @ManyToOne(fetch=FetchType.EAGER,optional=false)  @JoinColumn(name="PRODUCT_ID",      referencedColumnName="SKU",insertable=false,updatable=false,      nullable=false,unique=true)   public Product getProduct() {     return product;  }  public void setProduct(Product product) {     this.product = product;  }
    	
    	@Column(name="ORDER_ID")
    	public Integer getOrderId() {
    		return orderId;
    	}
    	public void setOrderId(Integer orderId) {
    		this.orderId = orderId;
    	}
    	
    	@Column(name="PRODUCT_ID")
    	public Integer getProductId() {
    		return productId;
    	}
    	public void setProductId(Integer productId) {
    		this.productId = productId;
    	}
      @ManyToOne(fetch=FetchType.EAGER,optional=false)  @JoinColumn(name="ORDER_ID",     referencedColumnName="ORDER_ID",insertable=false,updatable=false,      nullable=false,unique=true)   public CustomerOrder getCustomerOrder() {     return customerOrder;  }  public void setCustomerOrder(CustomerOrder customerOrder) {     this.customerOrder = customerOrder;  }
    
    }

    Класс LineItem имеет свойство CustomerOrder. Здесь, как показано выше, определено отношение типа многие-к-одному. Аналогично, класс LineItem также имеет отношение типа многие-к-одному к объекту product.

    Другой вид связывания используется, когда таблица может иметь отношение один-к-одному, а Ваша модель объекта имеет только один объект. Другими словами, Вы хотите связать один объект с несколькими таблицами (как бы противоположность зависимого объекта). Вы можете это сделать, добавив одну или несколько вторичных таблиц. Ниже приведен пример, который связывает объект customer с таблицами Customer и Order.

    Листинг 29
    @Entity
    @Table(name="CUSTOMER")
    @SecondaryTable(name="ORDER ",
    pkJoin=@PrimaryKeyJoinColumn(name="CUST_ID"))
    public class Customer { ... }
  8. Ограничения: аннотации и базы данных

    Кроме поддержки различных ограничений на уровне баз данных, JPA позволяет определять ограничения для отношений:

    Листинг 30
    @OneToMany(mappedBy="customerOrder", cascade=CascadeType.ALL , 
    fetch=FetchType.EAGER)
    	public Collection<LineItem> getLineItems() {
    		return lineItems;
    	}
    	public void setLineItems(Collection<LineItem> lineItems) {
    		this.lineItems = lineItems;
    	}

    В этом примере показан каскадный эффект. Например, если заказчик будет удален, то удалится и заказ. Ниже приведен пример с большим количеством ограничений:

    Листинг 31
    @ManyToOne(fetch=FetchType.EAGER,optional=false)
    @JoinColumn(name="CUSTOMER_ID", referencedColumnName="CUST_ID",
    	insertable=false,updatable=false, nullable=false,unique=true) 
    
    public Customer getCustomer() {
    	return customer;
    }
    public void setCustomer(Customer customer) {
    	this.customer = customer;
    }

    В примере выше внешний ключ, который также является частью первичного ключа, задает отношение многие-к-одному. Здесь никому не разрешается обновлять или модифицировать наш столбец, который к тому же помечен как уникальный и непустой. Отношение также определено как обязательное. JPA также позволяет определять уникальные ограничения на конкретные сущности, как показано далее:

    Листинг 32
    @Entity
    @Table(
    name="EMPLOYEE",
    uniqueConstraints=
    {@UniqueConstraint(columnNames={"EMP_ID", "EMP_NAME"})}
    )
  9. Наследование: аннотации – одиночная таблица, связанная таблица и таблица на класс

    Спецификация JPA определяет три вида поддержки для наследования связей, но только одна является обязательной в текущей спецификации:

    • Одиночная таблица: Дерево объектов привязано к одной таблице.
    • Связанная таблица: (необязательно) дочерний класс связывается с таблицей, которая имеет отношение посредством внешнего ключа к таблице, с которой связан родительский класс.
    • Таблица на класс: (Optional) (необязательно) каждый конкретный подкласс связан со своей таблицей и содержит столбцы для атрибутов надкласса.

    Вот пример связывания надкласса и подкласса с помощью одиночной таблицы:

    Листинг 33

    Кликните, чтобы увидеть код

    Листинг 33

    @Entity
    @Table(name="CUST")@Inheritance(strategy=SINGLE_TABLE,discriminatorType=STRING,discriminatorValue="CUST")
    public class Customer { ... }
    
    
    @Entity
    @Inheritance(discriminatorValue="VCUST")
    public class ValuedCustomer extends Customer { ... }

    Вот пример использования подхода связанной таблицы:

    Листинг 35
    @Entity
    @Table(name="CUST")@Inheritance(strategy=JOINED,discriminatorType=STRING,discriminatorValue="CUST")
    public class Customer { ... }
    
    @Entity
    @Table(name="VCUST")@Inheritance(discriminatorValue="VCUST")@PrimaryKeyJoinColumn(name="CUST_ID")
    public class ValuedCustomer extends Customer { ... }

В разделе Ресурсы можно найти информацию о множестве других возможностей, которые предоставляет JPA.


JAX-WS

В Java EE 5 также вводится новая модель программирования для Web-сервисов: JAX-WS. Прежде чем ознакомиться с новыми возможностями, давайте остановимся на том, что в JAX-WS осталось неизменным со времен JAX-RPC:

  • JAX-WS все еще поддерживает SOAP 1.1 по HTTP 1.1, так что совместимость не будет нарушена. Сообщения будут успешно передаваться в том же виде.
  • JAX-WS по-прежнему сохраняет поддержку WSDL 1.1, так что все, что Вы знали об этой спецификации, будет полезно. Новая спецификация WSDL 2.0 близка к завершению, но она все еще находилась в процессе разработки, когда была завершена разработка JAX-WS 2.0.

Подробная информация о JAX-WS представлена в серии статей Секреты Web-сервисов: JAX-RPC против JAX-WS, а здесь приводится краткий обзор изменений в JAX-RPC 2.0 по сравнению с JAX-WS 1.1:

  • SOAP 1.2: JAX-RPC и JAX-WS поддерживают SOAP 1.1. JAX-WS также поддерживает SOAP 1.2.
  • XML/HTTP: В спецификации WSDL 1.1 было определено HTTP-связывание. Это инструмент, с помощью которого можно посылать XML сообщения через HTTP без использования SOAP. В JAX-RPC не было возможности осуществить HTTP-связывание. В JAX-WS эта поддержка была добавлена.
  • Базовые профили WS-I: JAX-RPC поддерживает базовые профили (BP) WS-I версии 1.0. JAX-WS поддерживает BP 1.1. (WS-I – это организация по обеспечению взаимодействия Web-сервисов)
  • Новые функциональные возможности Java: JAX-RPC связан с Java 1.4. JAX-WS связан с Java 5.0. В JAX-WS используется множество новых функциональных возможностей Java 5.0. (в Java EE 5, которая идет на смену J2EE 1.4, добавлена поддержка JAX-WS, но также сохраняется поддержка JAX-RPC, что может запутать новичков в Web-сервисах.)
  • Модель отображения данных: JAX-RPC обладает собственной моделью отображения данных, которая покрывает около 90 процентов всех типов схем. Те типы, которые она не покрывает, привязаны к javax.xml.soap.SOAPElement. (В JAX-WS в качестве модели отображения данных используется JAXB, которая обещает поддержку отображения для всех XML-схем.)
  • Модель отображения интерфейсов: Базовая модель отображения интерфейсов JAX-WS не сильно отличается от модели JAX-RPC, однако модель JAX-WS использует новые возможности Java 5.0 и вводит функциональность асинхронного выполнения.
  • Динамическая модель программирования: Динамическая модель клиента JAX-WS существенно отличается от модели JAX-RPC. Большинство изменений продиктовано потребностями отрасли, включая динамическую и ориентированную на сообщения асинхронные функциональности. JAX-WS также включает динамическую серверную модель, которая отсутствует в JAX-RPC.
  • Механизм оптимизации передачи сообщений (MTOM): JAX-WS в рамках JAXB добавляет поддержку MTOM - новой спецификации для приложений. Это обещает сделать реальностью взаимодействие приложений.
  • Модель обработчиков: Модель обработчиков JAX-WS заметно изменилась по сравнению с JAX-RPC. Обработчики JAX-RPC основывались на SAAJ 1.2, тогда как обработчики JAX-WS полагаются на новую спецификацию SAAJ 1.3.

Кроме того, JAX-WS вместе с EJB 3.0 помогает упростить модель программирования. Например, код ниже показывает, как просто можно использовать EJB 3.0 POJO в Web-сервисе:

Листинг 35
@WebService public interface StockQuote {
    public float getQuote(String sym);
}

@Stateless public class QuoteBean implements StockQuote {
	public float getQuote(String sym) { ... }
}

Были добавлены также другие аннотации для поддержки более сложных возможностей Web-сервисов. JAX-B предоставляет стандартный механизм отображения между POJO (Листинг 36) и XML-схемами (Листинг 37). Пример таких отображений приведен ниже:

Листинг 36
@XmlType
public class Trade {
	@XmlElement(name="tickerSymbol")
	public String symbol;
	@XmlAttribute
	int getQuantity() {...}
	void setQuantity() {...}
}
Листинг 37
<xs:complexType name="trade">
	<xs:sequence>
	<xs:element 
		name="tickerSymbol"
		type="xs:string"/>
	</xs:sequence>
	<xs:attribute name="quantity"
		type="xs:int"/>
</xs:complexType>

JavaServer Faces

Спецификация JavaServer™ Faces (JSF) существует уже несколько лет и поддерживается большинством серверов приложений Java EE, такими как IBM® WebSphere Application Server. В Java EE 5 JSF стала частью спецификации Java EE 5. JSF предоставляет множество преимуществ для приложений Java EE:

  • Функционально насыщенные, расширяемые компоненты пользовательского интерфейса.
  • Архитектура, основанная на событиях.
  • Управляемое состояние компонентов.
  • Независимость обработчика/клиента.
  • Валидаторы.
  • Преобразование типов.
  • Вывод вовне навигации.
  • Общий язык выражений JavaServer Pages and Faces Expression Language.

В ожидании Java EE 6

Недавно было представлено предложение JSR 316 (Java EE 6), и хотя оно еще находится на ранней стадии определения спецификации, можно выделить несколько основных моментов:

  • Расширяемость: Добавление еще новых точек расширения и интерфейсов сервис-провайдеров позволяет эффективно и аккуратно внедрять другие технологии в реализацию платформы, обеспечивая развитие.

  • Профили: Профили будут связаны с платформой Java EE, как определено процессом JCP и могут включать подмножество технологий платформы Java EE, дополнительные JCP-технологии, не являющиеся частью базовой платформы Java EE, или оба вида технологий. Экспертная группа также определит первую версию Web-профиля Java EE - подмножество платформы Java EE, нацеленное на разработку Web-приложений.

  • Исключение ненужных составляющих: Некоторые технологии, включенные в платформу Java EE более не являются такими важными, как они были сразу после их введения в платформу. Вот почему был необходим способ «исключить» эти технологии из платформы осторожно и в нужной последовательности, так, чтобы не навредить разработчикам, которые до сих пор используют эти технологии, и в то же время обеспечить еще большее развитие платформы. Согласно определенному для этих целей процессу, экспертная группа будет рассматривать технологии, которые возможно будут убраны в будущих спецификациях платформы Java EE. Таковыми, возможно, будут являться:

    • EJB CMP, успешно замененная Java Persistence.
    • JAX-RPC, успешно замененная JAX-WS.
  • Поддержка SOA: Платформа Java уже активно используется для приложений SOA. В условиях, когда все больше и больше организаций осознают преимущества SOA архитектуры, неуклонно возрастают требования к платформе, как в плане функциональности, так и в плане взаимодействия. От Java EE 6 потребуется рассмотреть поддержку дополнительных Web-сервисов. Хотя базовая поддержка Web-сервисов на данный момент входит в платформу Java EE 6, спецификация потребует новых версий технологий, которые будут предоставлять поддержку дополнительных Web-сервисов. Архитектура Service Component Architecture (SCA) определяет средства, которые могут быть использованы композитными приложениями в среде SOA. Экспертная группа рассматривает вопрос о том, следует ли включать какие-либо средства, определенные в SCA, в платформу Java EE 6.

  • Другие добавления: Экспертная группа запланировала включить в Java EE 6 следующие новые JSR:

    • JSR-196 SPI Java-аутентификации для контейнеров.
    • JSR-236 Таймер для серверов приложений.
    • JSR-237 Администратор для серверов приложений.
    • JSR-299 Web Beans.
    • JSR-311 JAX-RS: Java API для Web-сервисов RESTful.

Ожидаются дальнейшие обновления в следующих областях:

  • Enterprise JavaBeans.
  • Java Persistence API.
  • Servlets.
  • JavaServer Faces.
  • JAX-WS.
  • Java EE Connector API.

Точный список включаемых технологий будет определен экспертной группой и будет обусловлен требованиями партнеров и клиентов. Некоторые из этих спецификаций будут также направлены на стремительно развивающееся пространство Web 2.0.


Выводы

Java EE 5 является содержательным и значительным релизом, делающим Java самой полной платформой для разработки корпоративных приложений. Безусловно, основные шаги стали ответом на критику в адрес разработки на Java в предыдущих версиях. EJB 3.0 и JPA - это мощные и простые в использовании технологии, а улучшения в JAX-WS позволяют осуществлять разработку Web-сервисов проще, чем когда-либо раньше.


Благодарности

Автор благодарит Джима Кнутсона (Jim Knutson) и Рассела Бьютека (Russell Butek) за их вклад в создание статьи.

Ресурсы

Научиться

Получить продукты и технологии

Обсудить

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=WebSphere, Технология Java, SOA и web-сервисы
ArticleID=254144
ArticleTitle=Познакомьтесь с Java EE 5
publish-date=09072007