EJB day1 Wednesday 2007.3.28
Enterprise JavaBeans
写EJB项目步骤:
1.建立EJB项目的路径。
2.设置CLASSPATH(类路径):
EJB目录/lib/javaee.jar //编译时
EJB目录/lib/appserv-rt.jar //运行时
如:liunx下配置
export CLASSPATH=.:opt/EJB/lib/javaee.jar:opt/EJB/lib/appserv-rt.jar:$CLASSPATH
3.写bean类,需要暴露的接口:Remote,Local
必须要有接口与实现类;远程通过接口中暴露的方法,向服务器发起调用,用服务器调用具体的实现类
public interface BeanRemote{
String m1(String v);
}
//只在服务器端有
//无状态模式
@Stateless
@Remote(BeanRemote.class)
public Bean implements BeanRemote{
String m1(String v){
//方法实现的代码
};
}
4.编译bean类。
5.打成jar包
6.部署到服务器上
7.(可选)写一个测试类测试
public class BeanTest {
public BeanTest() {}
public static void main(String[] args) throws NamingException {
//设置远程访问的IP地址
System.setProperty("org.omg.CORBA.ORBInitialHost","192.168.12.41");
InitialContext context=new InitialContext();
//在上下文中查询
BeanRemote beanRemote=(BeanRemote) context.lookup(BeanRemote.class.getName());
//调用BeanRemote的方法
String s=beanRemote.m1("abc");
}
}
==============================================================================================
EJB day2 Thursday 2007.3.29
1.Stateless Session Bean
特点:存入Bean pool,无成员属性保存数据
Stateful Session Bean
特点:存入cache中,成员属性保存数据,只供各自客户端使用
2.Lifecycle of Session Bean(生命周期)
------------------------------------------------
Stateless and Stateful 注释
@Stateless :声明该Session Bean是无状态的
@Stateful :声明该Session Bean是有状态的
*写这些注释的方法的标准:public void method() //只有method可自己命名
@PostConstruct :在Session Bean创建后,调用该方法
@PreDestroy :在Session Bean销毁前,调用该方法
@Remove :(Stateless 中无用)接口中暴露该方法,由客户端主动调用该方法,调用后会销毁Session Bean,销毁前会调用@PreDestroy(有则调用)
Stateful 注释
@PrePassivate :内存cache中Session Bean被用完时,回根据配置的策略选一个Session Bean存到磁盘中(叫遁化)前调用该方法
@PostActivate :从磁盘中取回数据到内存cache中后,调用该方法
三中策略:
LRU:最近最少使用策略
FIFO:先进先出策略
NRU:(Not Recently Used)这种近似LRU算法,已经退化成一种"最近不用"的算法
3.NetBeans 5.5使用
一般端口设置:
Admin port:4848
Domain Http port:8080
ORB Listener Port:3700
HTTPS port 8181
用NetBeans写EJB
选择新建项目:企业(Enterprise)->企业应用(EnterpriseApplication)[选择创建EJB模块,客户段模块]
在EJB模块->源包(Source)中建一个会话bean(Session bean)
1).//远程借口类session class
@Remote
public interface CountRemote{
int count();
@Remove
void remove();
}
2).//接口实现类session class
@Stateful
//如果使用拦截器,需要在这里配置,拦截器的类
@Interceptors({CountInterceptor.class})
public class CountBean implements CountRemote{
private int val;
public int count(){//实现代码};
@Remove
public void remove(){//实现代码};
/*
//如果拦截器中有了该方法就不用写在该类中了
@Postconstruct
public void construct(){//实现代码};
*/
}
3).//拦截器(可选)java class
public class CountInterceptor{
@PostConstruct
public void construct(){//实现代码};
@preDestroy
public void destroy(){//实现代码};
@PrePassivate
public void passivate(){//实现代码};
@PostActivate
public void activate(){//实现代码};
}
4).//测试类(可选) java main
创建Enterprise Applicaton Client(不通用,只有sun公司提供),提供了EJB运行环境容器
public class CountTest {
//创建EJB Session bean
//注入的方式创建bean,提供了运行环境容器
@EJB
private static CountRemote countRemote;
public CountTest() {
}
public static void main(String[] args) {
//可以直接使用,不关心如何获得
int i=countRemote.count();
countRemote.remove();
}
}
5.//配置EJB配置文件下的sun-ejb-jar.xml
Bean pool:(Stateless)
稳定池大小:
调整数量:
最大池数量:
池空闲超时秒数:
Bean cache:(Stateful)
最大缓存大小:
调整数量:
是否允许缓存溢出:(有些不支持)
缓存空闲超时秒数:
删除超时秒数:>100
牺牲者选择策略:LRU
==============================================================================================
EJB day3 Friday 2007.3.30
WebService:主要目标是跨平台的可互操作性。为了达到这一目标,WebService完全基于XML(可扩展标记语言)、XSD(XMLSchema)等独立于平台、独立于软件供应商的标准,是创建可互操作的、分布式应用程序的新平台。
1.用EJB生成WebService
1)写Session Bean(声明为WebService);
@Stateless
//声明生成WebService发布,服务名(serviceName):AdderService,(portName):AdderSerevicePort
@WebService(serviceName="AdderService",portName="AdderServicePort")
public class AdderBean implements AdderLocal {
/** Creates a new instance of AdderBean */
public AdderBean() {
}
//声明该方法在WebService中发布,如果所有的方法都不加,默认都发布
@WebMethod
public int add(int a, int b) {
//TODO implement add
return a+b;
}
}
2).部署(Deploy)到服务器上.在浏览器上获取他的地址(http://localhost:8080/AdderService/AdderBean?WSDL)
生成的是xml文档
3).在客户端创建Web Service Client->WSDL URL:http://localhost:8080/AdderService/AdderBean?WSDL
创建成功会访问服务器把应用下载到本地,生成相关的java.class和*.java等文件.包括:
AdderService.java:连接WebService的静态类,获取AdderBean的实体
AdderBean.java:只是接口(暴露所提供的方法),以便我们调用
4).(可选)写一个测试类,创建一个java main class
package test;
import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
public class AdderTest {
public AdderTest() {}
public static void main(String[] args) throws MalformedURLException {
//静态
/获取服务对象
AdderService service=new AdderService();
//获得Session Bean
AdderBean adderBean=(AdderBean)service.getAdderServicePort();
//调用他暴露的方法
System.out.println(adderBean.add(12,23));
//动态
URL wsdlURL=new URL("http://localhost:8080/AdderService/AdderBean?WSDL");
QName serviceName=new QName("http://day03/", "AdderService");
Service service2=Service.create(wsdlURL,serviceName);
adderBean=(AdderBean)service.getAdderServicePort();
System.out.println(adderBean.add(12,23));
}
}
2.Message Service(JMS)
创建queue message服务(点对点),发送者,接收者
发送者->queue message->一个接收者
1).在sun java System Application Server上创建消息转发:
Application Server->Resources->JMS Resources->Connection Factories->new[JNDI Name=jms/cfA Type=javax.jms.ConnectionFactory{自动区别queue或topic}]
Application Server->Resources->JMS Resources->Destination Resources->new[JNDI Name=jms/queueA Type=javax.jms.Queue name={必须有,随便输}]
2).客户端必须创建Enterprise Applicaton Client下创建发送者,和接收者
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class Sender {
public Sender() {}
public static void main(String[] args) throws Exception {
System.setProperty("jndi.factory","com.sun.jndi.cosnaming.CNCtxFactory");
System.setProperty("jndi.provider.url","corbaloc::localhost:3700/NameService");
Context context=new InitialContext();
ConnectionFactory cf=(ConnectionFactory) context.lookup("jms/cfA");
/*
//等价上面2行
context context2=context.lookup("jms");
ConnectionFactory cf2=context2.lookup("cfA");
*/
Queue queueA=(Queue) context.lookup("jms/queueA");
Connection con=cf.createConnection();
//false不支持事务(自动通知接收者),手动通知
Session session=con.createSession(false,Session.AUTO_ACKNOWLEDGE);
MessageProducer producor=session.createProducer(queueA);
TextMessage msg=session.createTextMessage();
msg.setText("***********");
producor.send(msg);
System.out.println("send completed!!!");
//关闭连接
con.close();
}
}
3.接收者
public class Receiver {
public Receiver() {}
public static void main(String[] args) throws Exception {
System.setProperty("jndi.factory","com.sun.jndi.cosnaming.CNCtxFactory");
System.setProperty("jndi.provider.url","corbaloc::localhost:3700/NameService");
Context context=new InitialContext();
ConnectionFactory cf=(ConnectionFactory) context.lookup("jms/cfA");
Queue queueA=(Queue) context.lookup("jms/queueA");
Connection con=cf.createConnection();
//false不支持事务(自动通知接收者),手动通知
Session session=con.createSession(false,Session.AUTO_ACKNOWLEDGE);
MessageConsumer consumer=session.createConsumer(queueA);
//必需告诉消息服务器,准备好了
con.start();
//没有接收到消息则阻塞,每次只接收一条消息
TextMessage msg=(TextMessage) consumer.receive();
System.out.println(msg.getText());
con.close();
}
}
==============================================================================================
EJB day4 Friday 2007.4.2
1.Message Service(JMS)监听器(监听者、接收者)
1).Message-Driven Bean(MDB):需要实现两个接口:
javax.jms.MessageListener
javax.ejb.MessageDrivenBean(可选)
它一般是无状态bean.生命周期有:@PostConstruct、@PreDestroy
用NetBeans写MDB
选择新建文件:[EJB 模块]->Enterprise->Message-Driven Bean(MDB)->[类名、包名、消息类别]
//mappedName:表示服务器上的DNJI名。
@MessageDriven(mappedName = "jms/queueA", activationConfig = {
//
@ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
//消息的类型;Queue:队列、Topic:主题
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue",
//(可选)消息选择器,JMSType='1':该监听器只接收类型为‘1’的消息,需要在发送者发送消息时著名类型:
@ActivationConfigProperty(propertyName = "messageSelector", propertyValue = "JMSType='1'"
)
})
public class Inserter implements MessageListener {
@Resource(name = "jdbc/sample")
private DataSource jdbcSample;
/** Creates a new instance of Inserter */
public Inserter() {
}
public void onMessage(Message message) {
if(message instanceof TextMessage){
//文本消息
TextMessage msg=(TextMessage) message;
//对象消息
// ObjectMessage msg=(ObjectMessage)message4;
request = msg.getText();
}
}
}
}
2. Return Results Back to Message Producers(发送者发送消息,并接收返回消息)
3.The Entity Class(实体)
1).用NetBeans写MDB
选择新建文件:[EnterpriseApplication-app-client]->Persistence(持久性)->Entity class->[类名、包名、创建持久性单元(选择数据库)]
2).为实体类写一个stateless Session Bean
@Stateless
public class AccountSLBean implements AccountSLRemote {
//注入持久性管理器
@PersistenceContext
private EntityManager em;
/** Creates a new instance of AccountSLBean */
public AccountSLBean() {
}
public void doSomething(){
Account a1=new Account();
a1.setBalance(1000);
a1.setOwerName("yoogo");
//持久化到数据库
em.persist(a1);
}
public Account findByPrimaryKey(Long id){
return em.find(Account.class,id);
}
public List findAll(){
String s="select a from Account a";
return em.createQuery(s).getResultList();
}
}
==============================================================================================
EJB day5 Tuesday 2007.04.03
1.EntityManager(实体管理器)中的方法
1). EntityManager.createQuery(String s);//等效于JDBC中的PreparedStatement()
Query query=entityManager.createQuery("select a from Acount a where name= :name");
query.setParamenter("name","hiloo");
2). EntityManager.createNameQuery("select * from acount");//直接使用SQL语句
3). EntityManager.createNamedQuery();//
类前面声明namedQuery
@NamedQuery(name="findAll",query="select a from Account a")
class AccountBean{
//....中间代码
Query query=entityManager.createNamedQuery("findAll");
2.实体管理器注释
@PersistenceContext(type=PersistenceContextType.EXTENDED) //用于stateful session bean
@PersistenceContext(type=PersistenceContextType.TRANSACTION) //用于stateless session bean
@Stateful
public class AccountSFBean implements AccountSFRemote {
unitName="EntityBean1-
@PersistenceContext(type=PersistenceContextType.EXTENDED)
private EntityManager em;
Account a;
public AccountSFBean() {}
public Account open(Long id,String name){
a=em.find(Account.class,id);
if(a==null){
a=new Account();
a.setOwerName(name);
em.persist(a);
}
return a;
}
public void deposit(double amount){
a.setBalance(a.getBalance()+amount);
}
public void withdraw(double amount){
a.setBalance(a.getBalance()-amount);
}
}
3.Entity Life cycle(实体的声明周期)
@PrePersist //持久化前调用该方法
@PostPersist //持久化后调用该方法
@PreUpdate //更新前调用该方法
@PostLoad //加载后调用该方法
举例:
1).写一个EntityListener(实体监听器)
public class AccountListener{
@PrePersist
public void prePersist(Account a){//代码块}
@Postpersist
//.... 同PrePersist
}
2).在Entity中注册EntityListener
@Entity
@EntityListeners(AccountListener.class)
public class Account implements Serializable{
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long accountno;
@Cloumn
private String name;
//...
}
实体的状态
new新建,也就是新建的实体实例,其信息还没有持久到数据库中。
managed受管状态,也就是实体已经持久化到数据库中,并且已经和持久化上下文进行了关联。
detached分离状态,也就是与持久化上下文解除关联的实体的状态
removed删除,此时实体和持久化上下文进行了关联,但是要从数据库中删除这个实体。
new persist() 中止PersistenceContext >
——>新建————>受管========================分离
||/ < merge()
remove()/|| persist()
删除
@PersistenceContext,持久化上下文是内存中的实例和数据库间的连接枢纽,就像是一快缓冲区,但这个缓冲区是由容器来进行管理的,在这个缓冲区中的实体是处在受管理状态。
@PersistenceContext(type=PersistenceContextType.EXTENDED,unitName="PetPU")
type属性使用来标识持久化上下文的类型的,持久化上下文有两种类型事务范围和扩展的。这两种类型的持久化上下文的生命周期不同。unitName属性是指定持久化单元的名字,其值是在持久化单元定义文件中persistence-unit标签中的name属性的值。
事务范围的持久化上下文应用到无状态SessionBean,一旦事务终结,就销毁,其中的实体也会变成分离状态。
扩展的持久化上下文应用在有状态的SessionBean,只有在有状态的SessionBean被容器销毁是才会销毁持久化上下文,也就使实体一直是被管理的。
持久化单元的定义文件,这个文件是描述数据库连接和事务管理的文件
<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">
<!--"JTA"用于容器状态;"RESOURCE_LOCAL":非容器-->
<persistence-unit name="PetPU" transaction-type="JTA">
<!--transaction-type是事务管理的类型-->
<provider>oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider</provider>
<!--SPI,持久化API的实现类的提供者-->
<jta-data-source>my.jdbc</jta-data-source>
<!--数据源的配置-->
<properties>
<property name="toplink.ddl-generation" value="create-tables"/>
</properties>
</persistence-unit>
</persistence>
EntityManager实体管理器,它是用来管理实体的,如果使用容器管理实体,容器就会注入EntityManager,EntityManager可以提供实体类生命周期管理,实现数据的同步,和实体的数据的查询。
实体生命周期回调方法
实体的生命周期回调方法不是通用的。
在实体类中定义时,只在方法前加标注,并且方法的返回值为void,方法为public
也就是:
@PrePersist
public void save(){}
在另外的类中写生命周期回调方法时,就需要以这个实体类为参数了
class AcountListenter{
@PrePersist
public void save(Acount a){}
}
@Entity
@EntityListenters(AcountListenter.class)
class Acount...
PostPersist
PreRemove
PostRemove
PreUpdate
PostUpdate
PostLoad