在路上

路上有惊慌,路上有理想

  BlogJava :: 首页 :: 联系 :: 聚合  :: 管理
  28 Posts :: 1 Stories :: 10 Comments :: 0 Trackbacks

#

1.linux安装字体
   以微软雅黑为例,找到msyh.ttf ,copy至下面的文件夹
   usr/share/fonts/msyh
  执行命令:fc-cache -fv
  重启jvm即可
2.drawString 部分代码
private static BufferedImage drawString(int type, boolean isWhite,
            int width, int height, String price, Font font_money, Font font,
            Graphics2D g2d, Rectangle2D bounds, Rectangle2D bounds_money) {
         BufferedImage image;
         //透明背景
          image = g2d.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT);  
         g2d.dispose();  
         g2d = image.createGraphics();  
         //反锯齿字体
         g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
         if(!isWhite){
             //非白字
             g2d.setColor(new Color(236,0,137));  
         }else{
             //白字
             g2d.setColor(new Color(255,255,255));  
         }
         //字体居中
         double y = (height - bounds.getHeight()) / 2;      
         double ascent = -bounds.getY();      
         double baseY = y + ascent;      

         g2d.setStroke(new BasicStroke(1));  
         g2d.setFont(font_money);
         g2d.drawString(FONT_RMB_CHAR, -2, (int)baseY);  
         g2d.setFont(font);
         g2d.drawString(price, (int)bounds_money.getWidth()-4, (int)baseY);
         g2d.dispose();
         return image;
    }
3.如果需要根据字符串的长度生成图片的宽度,可以使用如下方法
 Rectangle2D bounds = font.getStringBounds(price, context);
 width = (int)(bounds.getWidth();

4.批量生成,使用java自带的线程池,并使用CompletionService,目的是在线程处理结束后得到生成成功的ProductId
      public boolean generateImagesBatch(){
          boolean flag=true;
          ExecutorService exec = Executors.newFixedThreadPool(8);
           CompletionService<CallBack> completionService=
                    new ExecutorCompletionService<CallBack>(exec);
          long startTime=System.currentTimeMillis();
              String sql="select productId,price from prod";
            List<Map> skuList = this.cmsJdbcTemplate.queryForList(sql);
            for(Map map:skuList){
                String prodId=((BigDecimal)map.get("productId")).toString();
                double price=((BigDecimal)map.get("price")).doubleValue();
                completionService.submit(new CreateImageConcurrent(prodId,price,FontEnum.ONE,false));               
                completionService.submit(new CreateImageConcurrent(prodId,price,FontEnum.TWO,false));            }
            long endTime=System.currentTimeMillis()-startTime;
            log.info("query db time>>>>>>>>>>>>>>"+endTime/1000);
            
            Future<CallBack> future;
            int count=skuList.size()*6;
            log.info("generateImagesBatch count:"+count);
            try {
                while(count>0){
                    future = completionService.take();
                    CallBack callBack = future.get();
                    if(null!=callBack){
                        count--; log.info("generateImagesBatch prod id:"+callBack.getSuccesMessage());                    }
                }
            endTime=System.currentTimeMillis()-startTime;
            log.info("create images time>>>>>>>>>>>>>>"+endTime/1000);
            log.info("generateImagesBatch success!");
            flag=true;
            } catch (ExecutionException e) {
                flag=false;
                log.error("generateImagesBatch fail::ExecutionException::"+e.getMessage());
            } catch (InterruptedException e) {
                flag=false;
                log.error("generateImagesBatch fail::InterruptedException::"+e.getMessage());
            }finally{
                exec.shutdown();
            }
            return flag;
      }
posted @ 2012-04-18 11:35 阮步兵 阅读(1847) | 评论 (0)编辑 收藏

以下只是一些概念


1.SemaphoreCountDownLatch
 
Semaphore 可用于控制特定资源请求(线程/操作)数量
 
CountDownLatch 在功能上类似于Semaphore。区别是,Semaphore允许一次一个线程的话,CountDownLatch可以允许多个线程在特定的时间一起执行。

2.CAS操作
  根据英文直译其实可以理解其含义,compare and set.

  CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)。如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值。否则,处理器不做任何操作。CAS 认为位置 V 应该包含值 A;如果包含该值,则将 B 放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可通常将 CAS 用于同步的方式是从地址 V 读取值 A,执行多步计算来获得新值 B,然后使用 CAS 将 V 的值从 A 改为 B。如果 V 处的值尚未同时更改,则 CAS 操作成功。

3.ABA问题

  因为在更改 V 之前,CAS 主要询问“V 的值是否仍为 A”,所以在第一次读取 V 以及对 V 执行 CAS 操作之前,如果将值从 A 改为 B,然后再改回 A,会使基于 CAS 的算法混乱。在这种情况下,CAS 操作会成功,但是在一些情况下,结果可能不是您所预期的。这类问题称为 ABA 问题

4.原子操作

   A与B两个操作。从执行A的线程看,当其他线程执行B时,要么B全部执行完成,要么一点都不执行。这样A与B互为原子操作。要保证数据状态的一致性,要在单一的原子操作中更新所有相关联的状态。

5.可见性
 
   在单线程环境下,读写操作都在一个线程内完成,不存在可见性问题。但是,当读与写操作不在同一个线程内时,就需要有可见性的要求——即可变的共享变量对所有线程都是可见的。

6.重排序

    JVM实现中,线程内部维持顺序化语义。如果程序的最终结果等同于它在严格的顺序化环境下的结果,那么指令的执行顺序就可能与代码的顺序不一致。这个过程通过叫做指令的重排序。比如Java存储模型允许编译器重排序操作指令,在寄存器中缓存数值,还允许CPU重排序,并在处理器的缓存中缓存数值。

   当然,在没有同步的多线程情况下,编译器,处理器,运行时安排操作的执行顺序可能完全出人意料。

7.内部锁

  每个Java对象都可以隐士的扮演一个用于同步的锁的角色。比如synchronized(object){},执行线程进入synchronized块 之前自动获得锁。无论是正确执行或是抛出异常,最终都会释放该锁。内部锁是一种互斥锁(mutex)——至多只有一个线程可以拥有锁。JDK中有该锁的实 现。

8.锁与内存

   锁不仅仅是关于同步与互斥,也是关于内存可见性的。为了保证所有线程都能访问共享变量的最新值,读和写的线程必须使用公用的锁进行同步。

9.锁与volatile

   加锁可以保证可见性与原子性,volatile只能保证可见性。

10.happen-before法则

  Java存储模型有一个happens-before原则,就是如果动作B要看到动作A的执行结果(无论A/B是否在同一个线程里面执行),那么A/B就需要满足happens-before关系。比如一个对象构造函数的结束happens-before与该对象的finalizer的开始


参考:https://www.ibm.com/developerworks/cn/java/j-jtp11234/

     http://www.ibm.com/developerworks/cn/java/j-5things5.html

     http://www.blogjava.net/xylz/archive/2010/07/03/325168.html

    《Java 并发编程实践》

posted @ 2010-12-15 18:18 阮步兵 阅读(1728) | 评论 (0)编辑 收藏

BTrace是一个实时监控工具,使用了java agent jvm attach技术,可以在product的情况下实时监控线上程序的运行情况。另,有插件可与visualVM一起使用。
不多说了,具体的可见:http://kenai.com/projects/btrace

下面介绍几个Helloworld示例:
主要使用了btrace命令:btrace [pid] class

pid可由jps命令快速查询

1.监控方法输入参数:
 @OnMethod(
                clazz="com.btrace.Person",
                method="/set.*/"
            )
            public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn, AnyType[] args) {
                println(pcn);
                println(pmn);
                printArray(args);
            }

执行btract命令
后台输出:
com.btrace.Person
setId
[1, ]……

2.监控方法返回值
  @OnMethod(
                 clazz="com.btrace.Person",
                 method="/get.*/",
                 location=@Location(Kind.RETURN)
               )  
     public static void defineclass(@Return String cl) {
           println(Strings.strcat("getValue ", cl));
           Threads.jstack();
       }
执行btract命令
后台输出:
getValue gum
com.btrace.TestThread.main(TestThread.java:23)

3.监控jvm内存使用情况
  @OnTimer(4000)
    public static void printMem() {
        println("Heap:");
        println(heapUsage());
        println("Non-Heap:");
        println(nonHeapUsage());
    }
执行btract命令
后台输出:
Heap:
init = 268435456(262144K) used = 26175176(25561K) committed = 251658240(245760K)
 max = 492175360(480640K)
Non-Heap:
init = 12746752(12448K) used = 5892104(5754K) committed = 13598720(13280K) max =
 100663296(98304K)
4.监控方法执行时间
   @TLS private static long startTime;
   
    @OnMethod(clazz="com.btrace.Person",method="setId")
    public static void onCall(){
        println("enter this method");
        startTime=timeMillis();
    }
   
    @OnMethod(clazz="com.btrace.Person",method="setId",location=@Location(Kind.RETURN))
    public static void onReturn(){
        println("method end!");
        println(strcat("Time taken ms",str(timeMillis()-startTime)));
    }
  后台输出:
   enter this method
   method end!
   Time taken ms0
5.监控Thread start
 @OnMethod(
        clazz="java.lang.Thread",
        method="start"
    )
    public static void func() {
        println("about to start a thread!");
    }
后台输出:about to start a thread!
posted @ 2010-12-10 18:30 阮步兵 阅读(3745) | 评论 (1)编辑 收藏

     摘要: 1.注意auto_increment mysql5.0在高并发下(每天近2亿)插入单表数据出现了死锁(偶现),查了下相关文档,发现是因为采用了auto-increment的主键带来的问题,造成Table级的死锁。 原因:对于auto_increment字段,innodb会在内存里保存一个计数器用来记录auto_increment的值,当插入一个新行数据时,就会用一个表锁来锁住这个计数器,所以会...  阅读全文
posted @ 2010-12-09 12:56 阮步兵 阅读(1643) | 评论 (2)编辑 收藏

一.限制设计——从结构上说,是利用封装技术,保证某一时刻只有一个活动访问某个对象。

方式主要三类,方法限制、线程限制和对象内限制

方法限制:

   1.方法内部限制:采用局部变量方式

   2.方法间传递限制:

         a.调用者copy:比如print(p) 可以改为print(new Point(p));

         b.接收者copy:Point p=new Point(p.x,p.y);

         c.标量参数:print(int x,int y);d.print(p.x,p.y);

线程限制:

     1.最简单的方法是将所有可变对象都放在一个线程内执行

               public display(){

                         new Thread(){

                                  public void run(){//do something here}

                      }.start()

                }

      2.线程私有成员变量

         最直接的办法是利用现有类:ThreadLocal.

        当然你可以利用Thread.currentThread()自己实现一个类似功能的类,但Thread.currentThread有限制,就是对特定线程的一类。

        而ThreadLocal则摆脱了这样的限制。而且在线程内对ThreadLocal私有变量的读写不需要同步。

对象限制

       在前面两种方法都不能做到对对象的限制访问时,你就不得不使用锁。但同时,也可以对对象内部及不同部分的访问进行结构上的限制。

     1.适配器模式

      比如 class Point{

                 public double x;

                 public double y;

                 public synchronized double getX(){};

                //……

      }

    采用对象限制的设计方式,会将synchronized 锁移除到一个其他对象里,这样就解脱了Point.

     like this

           class SychPoint {

                 private final Point point=new Point();

                public synchronized double getX(){point.x}

         }

    class Point{

                 public double x;

                 public double y;

                 public double getX(){};

      }

    说白了就是采用适配器模式,改变了一下原来类的结构。java.util.Collection framework 里面就是使用这种策略组织起集合类的同步。

   2.子类化

       将锁延迟到子类实现,这里将不再罗嗦。

二.同步设计

     使用锁的注意事项

       1.有些入口锁在只有少数线程访问的情况下,可以很好的工作,开销并不大。但是当并发量变大,竞争加剧,开销也变大,系统的性能会随之下降。大多数线程会把大部分时间浪费在等待上。系统出现了延迟,限制了并发系统的优越性。

       2.使用太多的锁,会增加系统负担,以及不可料的情况发生,比如死锁。

       3.只用一把锁来保护一个功能的多个方面会导致资源竞争。

       4.长时间持有锁,会带来性能问题和异常处理的复杂。

       5.有时候加锁并不一定能保证得到我们想要的结果。

    对付以上这些问题,没有什么最佳策略,大都需要去权衡各个方面的利弊来进行设计。写多线程的程序,前期的设计比后期维护更为重要。

    初期的设计原则,

        1.减少同步

             a.用户可以接受陈旧数据,可以拿掉同步,使用volatile

             b.用户在得到非法数据时,只要能得到提示就够了,可以使用double-check方法。

                在不同步时check一次,再在同步状态在check一次。这么做的意义在于缩小锁使用范围,在第一次check不满足的情况,跳出方法,那么锁也就用不到了。

             c.只对维护状态部分加锁:当对象的某个同步方法是比较耗时的操作,那么锁持有的时间就越长,而仅仅是为了保持一个状态是,可以采用openCall的方式,减少持有锁时间。

                              public sychronized void updateState(){}

                              public void readFile(){

                                      updateState();//持有锁

                                    file.read();

                               }

               如上,这种方式的前提是程序不需要同步一个方法中无状态的部分。如果整个方法都需要锁,那这种方式就不适用了.

            D.能使用同步块,就不需同步整个方法。

     2.分解同步:

        分解类

            将锁拆分到辅助类中

        分解锁

           如果不愿分解类,可以设计分解锁

                    private static Object lock1 = new Object();

                   private static Object  lock2 = new Object();

                  synchronize(lock1){}

                  synchronized(lock2){}

              在jdk 5.0之后的并发包里,已有可重入锁供使用。

          隔离成员变量

              Person的age,income等属性都需要同步处理,以保证并发修改时,可以设计一些同步的int,Double等类型(util.concurrent已提供类似的类),将锁交给辅助类去处理。起到隔离作用.

 

posted @ 2010-11-11 17:47 阮步兵 阅读(1731) | 评论 (0)编辑 收藏

Java 内存模型

JVM系统中存在一个主内存(Main Memory),Java中所有变量都储存在主存中,对于所有线程都是共享的。每条线程都有自己的工作内存(Working Memory),工作内存中保存的是主存中某些变量的拷贝,线程对所有变量的操作都是在工作内存中进行,线程之间无法相互直接访问,变量传递均需要通过主存完成。

模型的规则:

1.原子性:保证程序得到成员变量(非局部变量)的值或者是初始值,又或者是某线程修改后的,绝对不是多个线程混乱修改后的。

2.可见性(共享内存的数据):什么情况下,写入成员变量的值对读取该变量的值是可见的?

     A.写操作释放了同步锁,读操作获得了同步锁

           原理:释放锁的时候强制线程把所使用的工作内存中的值刷新到主存,获得锁的时候从主存重新装载值。

           p.s.锁只被同步块和方法中的操作占有,但却控制了执行该操作的线程的所有成员变量。

     B.如果一个成员变量为volatile,那么在写线程做存储操作前,写入这个成员变量的数据会在主存中刷新,并对其他线程可见。读线程每次使用这个成员变量前都要重新从主存读数据。

     C.如果一个线程访问一个对象的成员变量,读到的值为初始值或者另一个线程修改后的值。

        p.s. 不要对引用未完全创建好的对象。

               如果一个类可以被子类化,那么在构造函数里启动一个线程是非常危险的

     D.当一个线程结束后,所有的写入数据都会被刷新到主存。

          p.s.同一个线程的不同方法之间传递对象的引用,永远不会有可见性问题

   存储模型保证:如果上面的操作都会发生,那么一个线程对一个成员变量的更新最终对另一个线程是可见的。

3.顺序化(内存操作的顺序):什么情况下,一个线程的操作可以是无序的?顺序化的问题主要围绕和读写有关的赋值语句的执行顺序。

   如果采用同步机制,那不用多说,顺序化可以保证。

   当没有同步机制时,存储模型所做的保证是难以相信的。在多线程环境下,存储模型是难以保证一定正确的。

  只有当满足下面的三个原则,顺序化才得以保证。

   A.从线程执行方法的角度看,如果指令都是串行执行的,那么顺序可以保证

   B.保证同步方法或块的顺序执行

   C.使用volatile定义成员变量

线程执行过程中,存储模型与锁的关系:

(1) 获取对象的锁

(2) 清空工作内存数据, 从主存复制变量到当前工作内存, 即同步数据

(3) 执行代码,改变共享变量值

(4) 将工作内存数据刷回主存

(5) 释放对象的锁

最后介绍一下volatile关键字

     volatile定义的成员变量可以保证可见性和顺序化,但不保证原子性。比如count++。
     *比如把一个变量声明为volatile,并不能保证这个变量引用的非volatile数据的可见性。比如volatile string[10](数组)

     正确使用volatile的前提条件

     a.对变量的写操作不依赖于当前值

     b.不要和其他成员变量遵守不变约束。见*处的解释

    volatile的应用

     a.状态标志

        volatile boolean shutdownFlag;

       public void shutdown() { shutdownFlag= true; }
       public void doWork() {
       while (!shutdownFlag) {
        // do something
         }

     b.假设一个后台线程可能会每隔几秒读取一次数据库里的合同金额,并更新至 volatile 变量。然后,其他线程可以读取这个变量,从而随时能够看到最新的金额。 比较广泛应用在统计类的系统中。

参考文档:

http://www.cs.umd.edu/~pugh/java/memoryModel/

http://www.ibm.com/developerworks/cn/java/j-jtp06197.html

《Java并发编程:设计原则与模式》

posted @ 2010-11-03 17:56 阮步兵 阅读(1441) | 评论 (0)编辑 收藏

1.迭代问题

  多线程环境下,迭代容易引起问题,如

  for(int i=0;i<v.size();i++){System.out.println(v.get(i))}

 解决办法之一:

     客户端加锁

     for(int i=0;true;i++){

                   Sychronzied(v){

                            if(i<v.size()){

                                 System.out.println(v.get(i)

                             }

               }

},当然这种也有问题,一旦程序可以重新设置元素位置,也会出错。

幸好有一种比较安全的办法: copy遍历对象

   Sychronzied(v){

                        Object v_clone= copy(v);

               }

     iterateV(v_clone);

2.Singleton

   单例习惯的方式,采用延时初始化,

   public static A getInstance(){

                   if(null==instance){

                     instance=new A();

                }

             return instance

   }

  在多线程模式下,需要加锁,来保证同步Sychronized(object){}。

如果初始化对象并不占用太多资源,其实没有必要加锁,毕竟同步也是很耗资源的。取消延时初始化,priavte static final instance=new A();

3.顺序化资源

   顺序化资源是避免死锁的简单的方式。

   死锁:T1时间,线程A 拥有objA的锁,请求objB的锁。线程B拥有objB的锁,请求objA的锁。

 如: System.identityHashCode(objA)<System.identityHashCode(objB)

 或者:public sychronized add(A a){sychronized(a){//do something}}

4.wait and notify

为了防止等待-通知机制出现race condition,需要加sychronized

race condition:objA在被wait之前已经被另一线程objB 给notify 了, 之后的wait 会永久停止,并导致deadlock(死锁),当然,如果你确认可以控制wait-notify很好,就不需要加了

posted @ 2010-10-28 11:45 阮步兵 阅读(1989) | 评论 (0)编辑 收藏


1.@Entity 标识实体
2.@Table (name = "tableName") //指定物理表

@Table(name="tbl_sky",
    uniqueConstraints = {@UniqueConstraint(columnNames={"month", "day"})}//唯一性约束
)

3.@Embeddable 被声明的类可以嵌入其他实体中
public class Address {
   private String street1;//persistent
   public String getStreet1() { return street1; }
   public void setStreet1() { this.street1 = street1; }
   private hashCode; //not persistent
}
@Embedded 在实体中嵌入一个类型:常用的像名字,地址之类的
另,使用@AttributeOverrides标识覆盖原类中的属性取值,因为原实体可能引用的是其他字段。
 @Embedded
    @AttributeOverrides( {
            @AttributeOverride(name="iso2", column = @Column(name="bornIso2") ),
            @AttributeOverride(name="name", column = @Column(name="bornCountryName") )
    } )
Country bornIn;

例子:
@Entity

class User {
  @EmbeddedId
  @AttributeOverride(name="firstName", column=@Column(name="fld_firstname")
  UserId id;
  Integer age;
}
@Embeddable
class UserId implements Serializable {//此处Serializable是必须的
  String firstName;
  String lastName;
}

4.@Access(AcessType.PROPERTY)
必须定义getter/setter方法才能实现持久化
还有另一种取值:AcessType.FILED,可以不定义getter/setter方法,也能实现持久化
此annotation也可以定义字段。

5.主键:
   A.单键
    @Id
    @GeneratedValue (generator = "identity")
    @GenericGenerator (name = "identity", strategy = "identity")
    或者
    @javax.persistence.SequenceGenerator(
    name="SEQ_STORE",
    sequenceName="my_sequence")
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ_STORE")
    其中:
     strategy取值为:
     AUTO - either identity column, sequence or table depending on the underlying DB
     TABLE - table holding the id
     IDENTITY - identity column
     SEQUENCE - sequence
   B.复合组键
    @Entity
 class Customer {
  @EmbeddedId CustomerId id;
  boolean preferredCustomer;
  @MapsId("userId")//user.id与customerId.userId 使用相同的值
  @JoinColumns({
    @JoinColumn(name="userfirstname_fk", referencedColumnName="firstName"),
    @JoinColumn(name="userlastname_fk", referencedColumnName="lastName")
  })
  @OneToOne User user;
}


@Embeddable
class CustomerId implements Serializable {
  UserId userId;
  String customerNumber;
}


@Entity
class User {
  @EmbeddedId UserId id;
  Integer age;
}

@Embeddable
class UserId implements Serializable {
  String firstName;
  String lastName;
}
     

6.字段设置:
@Column(
    name="columnName";
    boolean un(2)ique() default false;
    boolean nu(3)llable() default true;
    boolean in(4)sertable() default true;
    boolean up(5)datable() default true;
    String col(6)umnDefinition() default "";
    String tab(7)le() default "";
    int length(8)() default 255;
    int precis(9)ion() default 0; // decimal precision
    int scale((10)) default 0; // decimal scale
@Transient 非持久化字段
@Basic 持久化字段
@Basic(fetch = FetchType.LAZY) basic 用于定义property的fetch属性
@Enumerated(EnumType.STRING) 标识enum persisted as String in database
@Lob  blob clob字段
@Formula("obj_length * obj_height * obj_width")//自定义输出
public long getObjectVolume()

7.Mapping关系
A.一对多或者一对一:
 @OneToOne(cascade = CascadeType.ALL) 一对一关系,级联关系为all
 @PrimaryKeyJoinColumn或者
 指定关联外键
 @JoinColumn(name="passport_fk")
 Passport passport,
 一对一的另一端只需@OneToOne(mappedBy = "passport"),passport为前一个实体声明的名字


@OneToMany(fetch = FetchType.LAZY , mappedBy = "adProduct")
@Cascade(value = {CascadeType.ALL,CascadeType.DELETE_ORPHAN})

@OrderBy(value = "id")  //排序
B.多对一:
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="adPosition_id",nullable=false)   
   

8.Fetch and Lazy
AnnotationsLazyFetch
@[One|Many]ToOne](fetch=FetchType.LAZY) @LazyToOne(PROXY) @Fetch(SELECT)
@[One|Many]ToOne](fetch=FetchType.EAGER) @LazyToOne(FALSE) @Fetch(JOIN)
@ManyTo[One|Many](fetch=FetchType.LAZY) @LazyCollection(TRUE) @Fetch(SELECT)
@ManyTo[One|Many](fetch=FetchType.EAGER) @LazyCollection(FALSE) @Fetch(JOIN)

9.Cascade

10.缓存

缓存的注释写法如下,加在Entity的java类上:

@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)

缓存的方式有四种,分别为:

  • CacheConcurrencyStrategy.NONE
  • CacheConcurrencyStrategy.READ_ONLY,只读模式,在此模式下,如果对数据进行更新操作,会有异常;
  • CacheConcurrencyStrategy.READ_WRITE,读写模式在更新缓存的时候会把缓存里面的数据换成一个锁,其它事务如果去取相应的缓存数据,发现被锁了直接就去数据库查询;
  • CacheConcurrencyStrategy.NONSTRICT_READ_WRITE,不严格的读写模式则不会对缓存数据加锁;
  • CacheConcurrencyStrategy.TRANSACTIONAL,事务模式指缓存支持事务,当事务回滚时,缓存也能回滚,只支持JTA环境。


11.No-Annotation 字段:

      If the property is of a single type, it is mapped as @Basic

      Otherwise, if the type of the property is annotated as @Embeddable, it is mapped as @Embedded

      Otherwise, if the type of the property is Serializable, it is mapped as @Basic in a column holding the object in its serialized version

      Otherwise, if the type of the property is java.sql.Clob or java.sql.Blob, it is mapped as @Lob with the appropriate LobType
posted @ 2010-10-12 16:52 阮步兵 阅读(3200) | 评论 (0)编辑 收藏

1.J2EE安全性介绍

说明性的安全性:通过安全结构描述的方式来代表应用程序的安全需求,安全结构一般包括安全角色,访问控制和验证要求等。在j2ee平台中部署描述符充 当了说明的安全性的主要工具。部署描述符是组件开发者和应用程序部署者或应用程序组装者之间的交流工具。应用程序的开发者用它来表示应用中的安全需求,应用程序部署者或应用程序组装者将安全角色与部署环境中的用户和组映射起来。

在程序运行时容器从部署描述符中提取出相应的安全策略,然后容器根据安全策略执行安全验证。说明的安全性不需要开发人员编写任何安全相关的代码,一切都是通过配置部署描述符来完成的。

可编程的安全性: 可编程的安全性在说明性的安全性的基础上,使安全敏感的应用可以通过调用被容器提供的API来对安全作出决断。这在说明性的安全性不足以满足企业的安全模型的情况是非常有用的。比如J2ee在servlet HttpServletRequest interface中各提供两个方法:
isUserInRole (HttpServletRequest)——判断用户角色
getUserPrincipal (HttpServletRequest) ——获得用户认证信息principal
另外,就是用户自定义登录认证,而不是使用J2EE的部署描述符里面的定义(三种登录认证类型)。

2.基于J2EE的认证与授权

提到安全性,就不能不说到两个概念:认证与授权。

认证是用户或计算设备用来验证身份的过程。授权是根据请求用户的身份允许访问和操作一段敏感软件的过程。 这两个概念密不可分。没有授权, 就无需知道用户的身份。没能认证,就不可能区分可信和不可信用户, 更不可能安全地授权访问许多系统部分。


因为之前的项目100% web方式,所以本文只讨论web应用的认证和授权。


A.认证方式:
Web客户端通常通过http协议来请求web服务器端的资源,这些web资源通常包括html网页、jsp(java server page)文件、java servlet和其他一些二进制或多媒体文件。在企业环境中,企业的某些资源往往要求只允许某些人访问,有些资源甚至是机密的或安全敏感的。因此对企业中 各种web资源进行访问控制是十分必要的。为了满足企业中的不同安全级别和客户化的需求,J2EE提供了三种基于web客户端的认证方式:

HTTP基本证(HTTP Basic Authentication)
HTTP基本验证 是HTTP协议所支持的验证机制。这种验证机制使用用户的用户名和密码作为验证信息。Web客户端从用户获取用户名和密码,然后传递他们给web服务 器,web服务器在指定的区域(realm)中验证用户。但需要注意的是,这种验证方法是不够安全的。因为这种验证方法并不对用户密码进行加密,而只是对密码进行基本的base64的编码。而且目标web服务器对用户来说也是非验证过的。不能保证用户访问到的web服务器就是用户希望访问的。

基于表单的证(Form-Based Authentication)
基于表单的验证 使系统开发者可以自定义用户的登陆页面和报错页面。这种验证方法与基本HTTP的验证方法的唯一区别就在于它可以根据用户的要求制定登陆和出错页面。基于 表单的验证方法同样具有与基本HTTP验证类似的不安全的弱点。用户在表单中填写用户名和密码,而后密码以明文形式在网路中传递,如果在网路的某一节点将 此验证请求截获,在经过反编码很容易就可以获取用户的密码。因此在使用基本HTTP的验证方式和基于表单的验证方法时,一定确定这两种方式的弱点对你的应 用是可接受的。

基于客户端证书的证(Client-Certificate Authentication)
基于客户端证书的验证方式要比上面两种方式更安全。它通过HTTPS(HTTP over SSL)来保证验证的安全性。安全套接层(Secure Sockets Layer)为验证过程提供了数据加密,服务器端认证,信息真实性等方面的安全保证。在此验证方式中,客户端必须提供一个公钥证书,你可以把这个公钥证书 看作是你的数字护照。公钥证书也称数字证书,它是被称作证书授权机构(CA)-一个被信任的组织颁发的。这个数字证书必须符合X509公钥体系结构 (PKI)的标准。如果你指定了这种验证方式,Web服务器将使用客户端提供的数字证书来验证用户的身份。 

B.授权模型:

代码授权(Code Authorization)
j2ee产品通过java 2 安全模型来限制特定J2SE的类和方法的执行,以保护和确保操作系统的安全。

调用者授权(Caller Authorization) ——这个是我们常用的方式
安全角色:安全角色是具有相同安全属性的逻辑组。比如是admin,Supervisor等。

用户和组:用户和组是在实际系统环境下的用户和用户的集合。它们对应者现实当中的人和群体。

访问控制:访问控制可以确保安全角色只能访问已授予它安全权限的授权对象。授权对象包括EJB的远程方法、web资源(html网页,jsp/servlet和多媒体或二进制文件)等。在j2ee中访问控制在应用程序描述文件中与安全角色关联起来。

映射:通过映射应用程序的系统管理员将实际系统环境中的用户与安全角色联系起来,从而是实际的用户拥有对企业资源访问的适当授权。 


C.部署描述符安全性相关介绍:

安全约束——定义那些资源是受约束访问的,以及认证通过后的授权范围
<security-constraint>                                //安全约束部分
<web-resource-collection>                         //受约束的web资源集
<web-resource-name>WRCollection</web-resource-name>  //资源集名
<url-pattern>/webtest.jsp</url-pattern>                  //资源的url表达式
<http-method>GET</http-method>                     //受约束的资源操作方法
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>                                    //对安全角色授权
<role-name>user</role-name>                        //安全角色名
</auth-constraint>
<user-data-constraint>
<transport-guarantee>NONE</transport-guarantee>
</user-data-constraint>
</security-constraint>
定义安全角色 <security-role> <description>this is a user</description> <role-name>user</role-name> </security-role>
基本的HTTP认证方式——使用不多
<login-config> //验证方式设置 <auth-method>BASIC</auth-method> //使用基本的HTTP验证方式 <realm-name></realm-name> </login-config>
基于表单的认证方式——使用较多
<login-config> <auth-method>FORM</auth-method> //使用基于表单的验证方式 <realm-name>Default</realm-name> //使用缺省的安全域 <form-login-config> <form-login-page>/login.html</form-login-page> //定义登陆页面 <form-error-page>/error.html</form-error-page> //定义出错页面 </form-login-config> </login-config>
基于证书的认证方式——与CA用户数据中心一起使用
<login-config> <auth-method>CLIENT-CERT</auth-method>
</login-config>
注:后两种均在项目中应用过。
以上三种认证方式都属于配置式登录认证。
还有一种是程序性(编程式)的登录认证,即通过web application自身进行验证,比较典型的是利用过滤器代理操作。
比如开源的acegi,使用它你将无需再web.xml里配置如此多的东西(当然,也多了许多acegi的配置)。

参考 http://www.ibm.com/developerworks/cn/java/l-j2eeSecurity/
     企业级Java安全性——构建安全的J2EE应用

posted @ 2010-09-27 11:52 阮步兵 阅读(939) | 评论 (0)编辑 收藏

对于做软件的人来说,唯一不变的就是变化。此为行业真理。而对于复杂业务系统的逻辑组件的定义不得不多考虑一下业务的可扩展性,来应对客户的变化。选择Rule Engine是一个不错的方案。

Drools 是用 Java 语言编写的开放源码规则引擎。Drools 允许使用声明方式表达业务逻辑。可以使用非 XML 的本地语言编写规则(这点很重要,本人之前曾用过自己公司的一套业务规则组件,无论是编写还是调试都很麻烦),从而便于学习和理解。并且,还可以将 Java 代码直接嵌入到规则文件中,使Drools 更加吸引人。简单的概括,就是简单使用,易于理解。而且它是免费的。

1.rule文件:
rule "rule name"  
    no-loop
    when
      customer : Customer( state == CustomerState.UNCENSORED )     
    then
        customer.setState(CustomerState.AUDITING);
        CustomerTask task=new CustomerTask();
        Post law=userService.getPostByPostCode(Constants.PostCode.ROOT_LAW);
        task.setAuditorPost(law);
        task.setEntityState(CustomerState.AUDITING);
        task.setEntityId(customer.getId());
        task.setEntityCode(String.valueOf(customer.getId()));
        task.setEntityType(Customer.class.getSimpleName());
        task.setTitle(customer.getName()+" test");
        taskService.assignmentTask(task);
        logger.info("CustomerTask Submit auditorTitle:" + task.getAuditorTitle());
end

这里面有个状态的条件判断state == CustomerState.UNCENSORED ,then 关键字后面的便是符合条件的处理逻辑,只要是java程度都可以看懂,比xml类的rule文件好懂了许多。

接下来
语法说明:


文件头部分:
package drools.java.demo;定义包名,等同于命名空间
import drools.java.demo.Machine;导入java类
global java.util.List myGlobalList;此关键字让规则引擎知道,myGlobalList对象应该可以从规则中访问.
function:
类似于公用方法的抽象,如下定义后,各个同一文件下的rule都可以使用
function void setTestsDueTime(Machine machine, int numberOfDays) {
    setDueTime(machine, Calendar.DATE, numberOfDays);
}
rule:定义了一个规则

rule "<name>"
<attribute>*
when
<conditional element>*
then
<action>*
end




<name> 即rule的名字标识

<attribute>:

常用的属性:
no-loop :true 条件结果更改后,修改此条件且定义为no-loop:true的规则不会再重新执行。
lock-on-active:true 可以看作是no-loop的加强版,当条件结果更改后,不但修改此条件的规则不会重新执行,文件中的任何规则(其 active-lock 属性被设为 true)不会重新执行。
salience:100 使用它可以让规则执行引擎知道应该启动规则的结果语句的顺序。具有最高显著值的规则的结果语句首先执行;具有第二高显著值的规则的结果语句第二执行,依此类推。当您需要让规则按预定义顺序启动时,这一点非常重要。

其他属性的解释请见http://downloads.jboss.com/drools/docs/5.1.1.34858.FINAL/drools-expert/html_single/index.html#d0e2607

when:填写条件的地方,比如:
Cheese( type == "stilton", price < 10, age == "mature" )或

Cheese( type == "stilton" && price < 10, age == "mature" )

then:业务规则的地方,略。

2.用法

规则文件定义好后,就该是怎么使用它了


如上图,file rule定义好后,就该是如何使用它了。最重要的两个类RuleBase和WorkingMemory

下面是一个example:
public class RulesEngine {
    private RuleBase rules;
    private boolean debug = false;
    public RulesEngine(String rulesFile) throws RulesEngineException {
        super();
        try {
            // Read in the rules source file
            Reader source = new InputStreamReader(RulesEngine.class
                    .getResourceAsStream("../../rules/" + rulesFile));

            // Use package builder to build up a rule package
            PackageBuilder builder = new PackageBuilder();

            // This will parse and compile in one step
            builder.addPackageFromDrl(source);

            // Get the compiled package
            Package pkg = builder.getPackage();

            // Add the package to a rulebase (deploy the rule package).
            rules = RuleBaseFactory.newRuleBase();
            rules.addPackage(pkg);

        } catch (Exception e) {
            throw new RulesEngineException(
                    "Could not load/compile rules file: " + rulesFile, e);
        }
    }
    public RulesEngine(String rulesFile, boolean debug)
            throws RulesEngineException {
        this(rulesFile);
        this.debug = debug;
    }
    public void executeRules(WorkingEnvironmentCallback callback) {
        WorkingMemory workingMemory = rules.newStatefulSession();
        if (debug) {
            workingMemory
                    .addEventListener(new DebugWorkingMemoryEventListener());
        }
        callback.initEnvironment(workingMemory);
        workingMemory.fireAllRules();
    }
}
RulesEngine构造方法演示了如何去读入一个rule文件,并构建了一个RuleBase对象(RuleBase 是一个包含了rule文件的所有规则的集合)
executeRules方法定义了如何使用规则文件中定义的那些内容,用RuleBase构建一个WorkingMemory对象,再执行fireAllRules()方法。
WorkingMemory 代表了与rulebase链接的session会话,也可以看作是工作内存空间。如果你要向内存中插入一个对象可以调用insert()方法,同理,更新一个对象使用update()方法。WorkingMemory还有一个setGlobal()方法,用来设置规则内可以引用的对象(相当于规则的全局变量)。

3.小技巧

  可以一次把所有的rule文件都载入内存中存放,这样就不用每次执行都读取文件。
  如果规则文件被修改,也可以用过一个方法来判断是否需要重新载入rule文件
  比如:根据文件的最后修改时间,与内存中对应对象的时间做比较
public boolean hasChange(List<RuleFile> ruleFileList){
        for(RuleFile ruleFile:ruleFileList){
            if(!ruleFile.getLastModifyTime().equals(ruleFileMap.get(ruleFile.getFileName()).getLastModifyTime())){
                return true;
            }
        }
        return false;
    }

注:具体的helloWorld 请见http://www.ibm.com/developerworks/cn/java/j-drools/#listing12,比我说得好多了。
posted @ 2010-09-25 17:48 阮步兵 阅读(5234) | 评论 (0)编辑 收藏

仅列出标题
共3页: 1 2 3 下一页