少年阿宾

那些青春的岁月

  BlogJava :: 首页 :: 联系 :: 聚合  :: 管理
  500 Posts :: 0 Stories :: 135 Comments :: 0 Trackbacks

#

package com.abin.lee.servlet.process;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ProcessServlet extends HttpServlet{
 public void init() throws ServletException {
  super.init();
 }
 @SuppressWarnings("rawtypes")
 protected void doPost(HttpServletRequest request, HttpServletResponse response)
   throws ServletException, IOException {
  String username=request.getParameter("username");
  String password=request.getParameter("password");
  System.out.println("username="+username);
  System.out.println("password="+password);
  
  ServletContext context = getServletContext();
  RequestDispatcher dispatcher = context.getNamedDispatcher("dispatcher");
  dispatcher.forward(request, response);


//  ServletOutputStream out=response.getOutputStream();
//  BufferedWriter writer=new BufferedWriter(new OutputStreamWriter(out));
//  writer.write("success");
//  writer.flush();
//  writer.close();
  
 }
 public void destroy() {
  super.destroy();
 }
}









package com.abin.lee.servlet.process;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import junit.framework.TestCase;

import org.easymock.EasyMock;
import org.junit.Before;
import org.junit.Test;
public class ServletMock extends TestCase{
 private static HttpServletRequest request =null;
 private static HttpServletResponse response=null;
 private static ServletContext context=null;
 private static RequestDispatcher dispatcher=null;
 private static ProcessServlet servlet=null;
 @Before
 public  void setUp(){
  request =EasyMock.createMock(HttpServletRequest.class);
  response=EasyMock.createMock(HttpServletResponse.class);
  context=EasyMock.createMock(ServletContext.class);
  dispatcher=EasyMock.createMock(RequestDispatcher.class);
  servlet=new ProcessServlet(){
   private static final long serialVersionUID = 7534303474286669635L;

   public ServletContext getServletContext(){
    return context;
   }
  };
 }
 @Test
 public void test() throws ServletException, IOException{
  EasyMock.expect(request.getParameter("username")).andReturn("abin").times(20000);
  EasyMock.expect(request.getParameter("password")).andReturn("varyall").times(20000);
  EasyMock.expectLastCall();
  EasyMock.replay(request);
  EasyMock.replay(response);
  servlet.doPost(request, response);
  EasyMock.verify(response);
  dispatcher.forward(request, response);
  StringWriter sw=new StringWriter();
  PrintWriter writer=new PrintWriter(sw, true);
  response.getOutputStream();
//  response.set
//  String line="";
//  String result="";
//  while((line=writer.)){
//   
//  }
//  BufferedReader reader=new BufferedReader(new InputStreamReader());
  
  
  
  
 }
}

posted @ 2012-11-04 22:29 abin 阅读(733) | 评论 (0)编辑 收藏

简单的JUnit测试

本文介绍在NetBeans开发工具中编写和运行JUnit单元测试的基础部分。测试一个应用程序是开发周期的一部分,编写和维护单元测试可以保证你源代码中独立的方法可以正常工作。

NetBeans IDE 6.9 中包含JUnit 3.5和JUnit 4.5两个版本,可自行选择。(关于使用JUnit的更多信息,参考www.junit.org。)

目录
一、新建Java测试包
二、创建Java类库
三、JUnit注释
四、简单的JUnit4测试方法
五、运行测试


一、新建Java测试包

用于存放JUnit测试类库的包
1.右击“测试包”>“新建”>“Java包”。
2.在“新建Java包”对话框中,输入包名,选择位置(位置最好为“测试包”,以便于区分源码包与测试包)。
3.“完成”即可。

二、创建java类库测试

用于为java类库文件创建测试。
1.右击要创建测试的类文件,选择“工具”>“创建 JUnit 测试”。
2.在“选择 JUnit 版本”对话框中,选择“JUnit 4”。
3.弹出“创建测试”对话框,在“创建测试”对话框中可以创建的测试命名、选择位置(最好选择测试包)。
注:NetBeans中第一次使用 IDE 创建测试框架时,IDE 会提示选择 JUnit 版本。选择JUnit4后会自动删除JUnit 3库,下次再创建时,会默认创建JUnit4的测试。

三、JUnit注释

JUnit注释跟在测试方法前,对测试方法的类型进行说明。

1.JUnit测试注释

测试注释:@Test 标注将方法标记为测试方法。

2.测试类、测试的初始化函数和释放方法

在 JUnit 4 中,可以使用标注来标记以下类型的初始化函数和释放方法。
测试类初始化函数:@BeforeClass 标注将方法标记为测试类初始化方法。测试类初始化方法只能运行一次,并且在测试类中的任何其他方法之前运行。
测试类释放方法:@AfterClass 标注将方法标记为测试类释放方法。测试类释放方法只能运行一次,并且在测试类中的任何其他方法完成之后运行。
测试初始化函数:@Before 标注将方法标记为测试初始化方法。测试初始化方法在测试类中的各测试用例之前运行。运行测试不需要测试初始化方法,但是,如果需要在
运行测试之前初始化一些变量,则可以使用测试初始化方法。
测试释放方法:@After 标注将方法标记为测试释放方法。测试释放方法在测试类中的各测试用例之后运行。运行测试不需要测试释放方法,但是,可能需要使用释放方法
来清理运行测试用例时所需的任何数据。

3.禁用测试注释

禁用测试:@Ignore 标注将该方法禁用。

四、简单的JUnit4测试方法

创建java类库测试后,分生成该类所有方法的测试方法。(测试方法很多)
断言
1.assertEquals( 期望值, 实际值 ) // 实际值用被测试方法代替时就是对该方法的测试
2.assertTrue( 实际值 )
3.assert False(实际值)
注:此方法使用 JUnit assertTrue 和 assertFalse 方法来测试各种可能的结果。要通过此方法的测试,assertTrue 必须全部为 true,并且 assertFalse 必须
全部为 false。
超时
4.@Test(timeout=1000) // 超时被设置为 1000 毫秒。
异常:
5.@Test(expected=IllegalArgumentException.class) // 返回异常
禁用测试:
6.@Ignore // 在@Test 上方添加 @Ignore 标注来禁用测试。

五、运行测试

1.运行单个测试:
右击要运行的测试,选择“运行文件”。
2.运行整个测试:
1)右击要运行的测试包,选择“新建”>“其它”打开“新建向导”。
2)类别选择“JUnit”,文件类型选择“测试套件”,点击“下一步”。
3)输入测试名,选择位置,及要测试的包。
4)“完成”即可。
此时运行这个测试套件即可运行包内的所有测试。
posted @ 2012-11-02 14:40 abin 阅读(1322) | 评论 (0)编辑 收藏

软件测试
___________________________________________________________________________
Unit Test是由程序员本身来编写的。

以下介绍Junit单元测试框架:官网地址www.junit.org

JUnit是由 Erich Gamma 和 Kent Beck 编写的一个回归测试框架(regression testing framework)。Junit测试是程序员测试,即所谓白盒测试,因为程序员知道被测试的软件如何(How)完成功能和完成什么样(What)的功能。

Junit3.x
___________________________________________________________________________

Junit3.x中使用包junit.framework.*

1.       必须继承TestCase类

public class CalculatorTest extends TestCase {

    private Calculator cal;

    public CalculatorTest() {

    }

    public CalculatorTest(String name) {

        super(name);

    }

    public void setUp() {

        System.out.println("...........setUp..............");

        cal = new Calculator();

    }

    public void testAdd() {

        int result = cal.add(1, 2);

        Assert.assertEquals("计算添加失败", 3, result);

         }

public void tearDown() {

        System.out.println("........tearDown........");

         }

}



2.       测试用例(Test Case)是单元测试的一个非常重要的方面。

3.       单元测试主要是用来判断程序的执行结果与自己期望的结果是否一致。

4.       在Junit3.x中,测试方法规则定义如下:

1)      public

2)      void

3)      无参数的

4)      测试方法名以test开头

5.       Test Case之间一定要保持完全的独立性,不允许出现任何的依赖关系。

6.       我们不能依赖于测试方法的执行顺序。

7.       关于setUp与tearDown方法的执行顺序:

1) setUp

2) testAdd

3) tearDown

8.       Junit两种类型错误,Failure 和 Error

Failure:指预期结果与实际结果不同,例如当你使用assertEquals或者assertXXX方法断言失败时,或者调用fail方法,就会报出Failure,这时要检查测试方法逻辑设计是否有误。

    public void testDevide() {

        System.out.println(".........testDevide()........");

        int expected = 0;

        int actual = 0;

        try {

            actual = cal.devide(1, 3);

        } catch (Exception e) {

            Assert.fail("测试失败"); //不应该执行这段.

        }

        Assert.assertEquals(expected, actual);

    }

         Error:指程序在断言执行之前,程序就因为某种错误而引发异常,导致程序终止,例如测试方法中因抛出某个异常,使得测试方法无法正确执行到断言就结束,这时你要检查测试的方法是否有未考虑到的情况而引起流程突然中断。

               也就是说代码中抛出了异常等影响代码正常执行的情况,比如ArrayIndexOfBoundsException、NullPointException,也可能是磁盘已满、网络中断等等外部环境失败所带来的影响。

首先处理Error,然后在处理Failure.

9.       运行测试用例

1)      IDE中,如Eclipse工具已经内置了Junit,所以可以直接在测试类中鼠标右键Run--Junit Test运行。



2)      使用junit.textui.TestRunner类运行测试类.

public static void main(String[] args) {

        junit.textui.TestRunner.run(MyStackTest.class);

        junit.textui.TestRunner.run(new CalculatorTest("testAdd"));

}

3)      使用TestSuite

a)        一次可以运行多个测试类进行测试

public class TestAll {
    public static Test suite() {
        TestSuite suite = new TestSuite();
        suite.addTestSuite(OOOTest.class);
        suite.addTestSuite(XXXTest.class);
        suite.addTestSuite(YYYTest.class);
        return suite;
    }
    public static void main(String[] args) {
        TestRunner.run(suite());
    }
}

b)        通过IDE自动发现suite()方法,必须继承TestCase

public class TestAll extends TestCase {
    public static Test suite() {
        TestSuite suite = new TestSuite();
        suite.addTestSuite(OOOTest.class);
        suite.addTestSuite(XXXTest.class);
        suite.addTestSuite(YYYTest.class);
        return suite;
    }
}

c)   组合模式,组合方式多元化

……

public static Test suite() {
        TestSuite suite = new TestSuite();
        suite.addTest(new XXXTest("testABC"));  // 执行testABC()方法
        suite.addTest(YYYTest.suite()); // suite() 传回TestSuite实例
        suite.addTestSuite(OOOTest.class);//自动查找OOOTest类中testXXX方法
        return suite;
    }

10.测试之前是什么状态,在测试执行完成后就应该是什么状态,而不应该由于测试执行的原因到导致了状态发生了变化。

Junit4.x
___________________________________________________________________________

Junit4.x开始支持Annotation注解技术,在编写测试用例时简化不少动作.
Junit4.x中使用的包org.junit.*

Junit4.x是兼容以前版本

Eclipse中自带了Junit4,版本为junit4.3.1. BC-EC工程中使用的版本为Junit4.4,目前最新版本4.11



1. 无需继承TestCase类,所有被@Test注解所修饰的public,void,无参数的方法都是测试用例,Junit自动查找注解方法并执行测试。

@Test

    public void testAdd() {

        int result = cal.add(1, 2);



        Assert.assertEquals("计算添加失败", 3, result);

}

2. 虽然Junit4.x中测试类中的方法名称可以随便取,但是建议跟junit3.x中测试类方法命名约定一致,统一方法名以test开头。

3. 使用@Before注解所修饰的方法同junit3.x中的setUp方法的功能,使用@After注解所修改的方法同junit3.x测试类中的tearDown方法的功能。 @Before和@After可以在多次指定.

@Before

    public void init() {

        System.out.println("...........setUp..............");

        cal = new Calculator();

}



@After

    public void destroy() {

        System.out.println("........tearDown........");

}

4. 通过@BeforeClass和@AfterClass注解标注public,static,void,无参数的类方法。在所有测试方法执行之前和之后执行。

@BeforeClass
public static void setUpBeforeClass() {
    ...
}
@AfterClass
public static void tearDownAfterClass() {
    ...
}

5. 使用@Ignore注解所修饰的方法(可以表示尚未编写完该用例或者想禁用该用例),运行器会忽略该方法的测试;当修饰类时,运行器会忽略掉所有测试方法。

@Test

    @Ignore("尚未完成")

    public void testMultiply() {

    … …

}

Eclipse中Junit执行结果中会提示如下:





6. 预期异常:

也可以使用在junit3.x中提到的fail()来测试预期抛出异常的情况。

public void testDevideByZero() {

        Throwable tx = null;

        try {

            cal.devide(1, 0);

            Assert.fail("应该按预期抛出异常,测试失败");

        } catch (Exception e) {

            tx = e;

        }

        Assert.assertNotNull(tx.getMessage());

        Assert.assertEquals(ArithmeticException.class, tx.getClass());

        Assert.assertEquals("除数不能为0!", tx.getMessage());

}

junit4中使用Test中的expected属性达到相同的功能,代码量小很多.

    @Test(expected = ArithmeticException.class)

public void testDevideByZero() throws Exception {

        cal.devide(1, 0); // 应该抛出异常

}

7. 使用@Test(timeout = 2000) 注解预期某些操作应该在指定时间内完成,否则测试失败。    单位是毫秒。

8. 测试运行器:可以使用@RunWith注解使用的runner.

Junit4中内置的运行器有:

a) 附带兼容junit3.x运行器

org.junit.internal.runners.Junit38ClassRunner

b) 参数化运行器,可设定一组参数,每次运行测试时自动在指定位置给予不同的参数。

org.junit.runners.Parameterized

c) Suite运行器,如同Junit3.x中的TestSuite, 用于任意组合测试.

org.junit.runner.Suite

9. 参数化运行器:

a) 使用注解@RunWith(value = Parameterized.class) 指定参数化运行器,

b) 定义好一个方法,返回一组参数数据,使用注解@Parameterized.Parameters

c) 测试类构造方法中为各个参数赋值(构造方法是由Junit调用的)

d) 方法必须是public,static,void,no-arg,返回一个Collection。

e) 方法中每个元素必须是一个一维数组,数组中第一个为预期值,之后参数一,参数二等。

@RunWith(value = Parameterized.class)

public class ParamCalculatorTest {



    private Calculator cal;

    private int expected;

    private int para1;

    private int para2;



    @Parameterized.Parameters

    public static Collection<Integer[]> getParamData() {

       Integer[][] data = new Integer[][] { { 5, 3, 2 }, { 3, 1, 2 }, { 2, 1, 1 } };

        return Arrays.asList(data);

    }



    @Before

    public void init() {

        cal = new Calculator();

    }



public ParamCalculatorTest(int expected, int para1, int para2) {

        this.expected = expected;

        this.para1 = para1;

        this.para2 = para2;

    }



    @Test

    public void testAdd() {

        int result = cal.add(para1, para2);

        Assert.assertEquals(expected, result);

}



    @After

    public void destory() {

    }

}



10.Suite运行器:在Junit4中,如果想同时运行多个测试,需要使用两个注解:

@RunWith(value = Suite.class)
@SuiteClasses

使用以上两个注解会通过Suite运行器来执行测试,在SuiteClasses中指定测试类,也可以继续指定Suite,这样Junit会在去查找里面的测试类并执行。

    @RunWith(value = Suite.class)

@SuiteClasses( { CalculatorTest.class, MyStackTest.class })

public class SuiteCalculatorMyStackTest {

    … …

}

posted @ 2012-11-02 14:16 abin 阅读(1279) | 评论 (0)编辑 收藏

myEclipse项目转成Eclipse开发

公司拿到手的项目开发平台都不统一。有的是myEclipse开发的,有的是Eclipse for J2EE开发的。

这里说一种把myEclipse项目转成Eclipse项目继续开发


1.  请首先确保你的eclipse是javaee版本的,或者已经安装看wtp插件


2.  然后修改eclipse工程下的.project文件:

3.在<natures></natures>中加入
    <nature>org.eclipse.wst.common.project.facet.core.nature</nature>
    <nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
    <nature>org.eclipse.jem.workbench.JavaEMFNature</nature>
4. 在<buildSpec>< ildSpec>中加入
    <buildCommand>
        <name>org.eclipse.wst.common.project.facet.core.builder</name>
        <arguments>
        </arguments>
    </buildCommand>
    <buildCommand>
        <name>org.eclipse.wst.validation.validationbuilder</name>
        <arguments>
        </arguments> 
     </buildCommand>
5. 刷新项目,项目->右击->Properties->Project Facets->Modify Project,选择Java和Dynamic Web Module配置Context Root 和Content Directory 以及源码路径
6. 第5步没有的话,找到项目的.setting目录,修改org.eclipse.wst.common.component  里面的
<wb-module   deploy-name= "Demo ">
<wb-resource   deploy-path= "/ "   source-path= "/WebRoot "/>

这两个即可,deploy-name   为工程名,source-   path= "/WebRoot "eclipse下默认为WebContent修改为WebRoot


svn
http://subclipse.tigris.org/update_1.6.x


-Xms512m -Xmx1024m -XX:PermSize=128m -XX:MaxNewSize=256m -XX:MaxPermSize=256m
posted @ 2012-11-01 09:38 abin 阅读(4338) | 评论 (0)编辑 收藏

1. 查看processes和sessions参数

SQL> show parameter processes

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
aq_tm_processes                      integer     1
db_writer_processes                  integer     1
job_queue_processes                  integer     10
log_archive_max_processes            integer     2
processes                            integer     150

 

SQL> show parameter sessions

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
java_max_sessionspace_size           integer     0
java_soft_sessionspace_limit         integer     0
license_max_sessions                 integer     0
license_sessions_warning             integer     0
logmnr_max_persistent_sessions       integer     1
mts_sessions                         integer     165
sessions                             integer     170
shared_server_sessions               integer     165
SQL>

 

2. 修改processes和sessions值

SQL> alter system set processes=300 scope=spfile;

系统已更改。

SQL> alter system set sessions=335 scope=spfile;

系统已更改。

3. 修改processes和sessions值必须重启oracle服务器才能生效

ORACLE的连接数(sessions)与其参数文件中的进程数(process)有关,它们的关系如下:

sessions=(1.1*process+5)

 

 查询数据库当前进程的连接数:

 select count(*) from v$process;

  查看数据库当前会话的连接数:

  select count(*) from v$session;

  查看数据库的并发连接数:

  select count(*) from v$session where status='ACTIVE';

  查看当前数据库建立的会话情况:

  select sid,serial#,username,program,machine,status from v$session;

 查询数据库允许的最大连接数:

  select value from v$parameter where name = 'processes';

  或者:show parameter processes;

  修改数据库允许的最大连接数:

  alter system set processes = 300 scope = spfile;

  (需要重启数据库才能实现连接数的修改)

  重启数据库:

  shutdown immediate;

  startup;

  查看当前有哪些用户正在使用数据:

  select osuser,a.username,cpu_time/executions/1000000||'s',sql_fulltext,machine

  from v$session a,v$sqlarea b

  where a.sql_address = b.address

  order by cpu_time/executions desc;

  备注:UNIX 1个用户session对应一个操作系统process,而Windows体现在线程。

  启动oracle

  su - oracle

  sqlplus system/pwd as sysdba   //进入sql

  startup                                      //启动数据库

  lsnrctl start                               //启动监听

  sqlplus "/as sysdba"

  shutdown immediate;

  startup mount;

  alter database open;

posted @ 2012-10-31 09:47 abin 阅读(1965) | 评论 (0)编辑 收藏

posted @ 2012-10-29 22:42 abin 阅读(996) | 评论 (0)编辑 收藏

一:安装
  1,如果是LINUX系统,可以到官方网址http://memcached.org/进行下载,安装教程网上一大堆,这里不再叙述。
  2,如果是WINDOWS系统

     - 到http://code.jellycan.com/memcached/下载稳定版。

     - 下载后解压到某个盘下面,比如在c:\memcached,在终端(也即cmd命令界面)下输入 ‘c:\memcached\memcached.exe -d install’ 安装。

     - 再输入: ‘c:\memcached\memcached.exe -d start’ 启动。

     - 修改memcache的内存大小,可以在注册表里找到HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/memcached Server,修改ImagePath的值为
“C:/memcached/memcached.exe” -d runservice -m 512
  NOTE: Windows版本一般用作开发调试只用,不建议在产品环境中使用。

二:JAVA连接使用Memcached
  1, 下载memcached客户端开发包,地址https://github.com/gwhalin/Memcached-Java-Client
  2,下面是一个连接并使用的简单例子

 

package com.ea.online.memcache;

import java.util.Date;

import com.danga.MemCached.MemCachedClient;
import com.danga.MemCached.SockIOPool;

public class MyClass {

    // create a static client as most installs only need
    // a single instance
    protected static MemCachedClient mcc = new MemCachedClient();

    protected static SockIOPool pool = null;
    // set up connection pool once at class load
    static {

        // Server list
        String[] servers = { "localhost:11211" };

        // Specify memcached capacity
        Integer[] weights = { 3, 3, 2 };

        /*
         * String[] serverlist = { "cache0.server.com:12345",
         * "cache1.server.com:12345" }; Integer[] weights = { new
         * Integer(5), new Integer(2) }; int initialConnections = 10; int
         * minSpareConnections = 5; int maxSpareConnections = 50; long
         * maxIdleTime = 1000 * 60 * 30; // 30 minutes long maxBusyTime = 1000 *
         * 60 * 5; // 5 minutes long maintThreadSleep = 1000 * 5; // 5 seconds
         * int socketTimeOut = 1000 * 3; // 3 seconds to block on reads int
         * socketConnectTO = 1000 * 3; // 3 seconds to block on initial
         * connections. If 0, then will use blocking connect (default) boolean
         * failover = false; // turn off auto-failover in event of server down
         * boolean nagleAlg = false; // turn off Nagle's algorithm on all
         * sockets in pool boolean aliveCheck = false; // disable health check
         * of socket on checkout
         *
         * SockIOPool pool = SockIOPool.getInstance();
         * pool.setServers(serverlist);
         * pool.setWeights(weights);
         * pool.setInitConn(initialConnections);
         * pool.setMinConn(minSpareConnections);
         * pool.setMaxConn(maxSpareConnections); pool.setMaxIdle(maxIdleTime);
         * pool.setMaxBusyTime(maxBusyTime);
         * pool.setMaintSleep(maintThreadSleep);
         * pool.setSocketTO(socketTimeOut); pool.setNagle(nagleAlg);
         * pool.setHashingAlg(SockIOPool.NEW_COMPAT_HASH);
         * pool.setAliveCheck(true); pool.initialize();
         */

        // grab an instance of our connection pool
        pool = SockIOPool.getInstance();

        // set the servers and the weights
        pool.setServers(servers);
        pool.setWeights(weights);

        // Specify main thread maintain frequency
        pool.setMaintSleep(30);

        // set some TCP settings
        // disable nagle
        pool.setNagle(false);
        // set the read timeout to 3 secs
        pool.setSocketTO(3000);
        // and don't set a connect timeout
        pool.setSocketConnectTO(0);

        // initialize the connection pool
        pool.initialize();


    }

    // from here on down, you can call any of the client calls
    public static void main(String[] args) {
        // Test expired
        mcc.set("foo", "This is a test String", new Date(
                new Date().getTime() + 3000));
        String bar = mcc.get("foo").toString();
        System.out.println("test-->" + bar);
        while (true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println(mcc.get("foo"));
        }
        // pool.shutDown();
    }
}

 

 

详细使用可以借鉴这篇文章:http://sillycat.iteye.com/blog/563615

三:结合AOP编程
  1,对于memcached与spring aop的集成网上又是一堆,这里不提了。
  2,对于memcached与guice aop的集成可参考http://code.google.com/p/google-guice/wiki/AOP
  3,对于需要通过手动实现动态代理的方式来实现AOP的可以参考 http://www.blogjava.net/DoubleJ/archive/2008/03/04/183796.html

四:一个简单的环绕通知切面,不可运行,仅作参考

public Around implements MethodInterceptor {
 ....
    public Object invoke(MethodInvocation mi, Object[] args) {
        Object obj = null;
        //从Memcached中获取
        obj = mcc.get(this.class.getName() + mi.getMethodName() + args.hashcode());
        if(obj != null) {
            return obj;
        }
      
        obj = method.invoke(args);
      
        //存入Memcached
        mcc.set(this.class.getName() + mi.getMethodName() + args.hashcode, obj, expiredDate);
        return obj;
    }
 ....

posted @ 2012-10-26 22:54 abin 阅读(1173) | 评论 (0)编辑 收藏

内存溢出与数据库锁表的问题,可以说是开发人员的噩梦,一般的程序异常,总是可以知道在什么时候或是在什么操作步骤上出现了异常,而且根据堆栈信息也很容易定位到程序中是某处出现了问题。内存溢出与锁表则不然,一般现象是操作一般时间后系统越来越慢,直到死机,但并不能明确是在什么操作上出现的,发生的时间点也没有规律,查看日志或查看数据库也不能定位出问题的代码。

更严重的是内存溢出与数据库锁表在系统开发和单元测试阶段并不容易被发现,当系统正式上线一般时间后,操作的并发量上来了,数据也积累了一些,系统就容易出现内存溢出或是锁表的现象,而此时系统又不能随意停机或重启,为修正BUG带来很大的困难。

本文以笔者开发和支持的多个项目为例,与大家分享在开发过程中遇到的Java内存溢出和数据库锁表的检测和处理解决过程。

2.内存溢出的分析
内存溢出是指应用系统中存在无法回收的内存或使用的内存过多,最终使得程序运行要用到的内存大于虚拟机能提供的最大内存。为了解决Java中内存溢出问题,我们首先必须了解Java是如何管理内存的。Java的内存管理就是对象的分配和释放问题。在Java中,内存的分配是由程序完成的,而内存的释放是由垃圾收集器(Garbage Collection,GC)完成的,程序员不需要通过调用GC函数来释放内存,因为不同的JVM实现者可能使用不同的算法管理GC,有的是内存使用到达一定程度时,GC才开始工作,也有定时执行的,有的是中断式执行GC。但GC只能回收无用并且不再被其它对象引用的那些对象所占用的空间。Java的内存垃圾回收机制是从程序的主要运行对象开始检查引用链,当遍历一遍后发现没有被引用的孤立对象就作为垃圾回收。

引起内存溢出的原因有很多种,常见的有以下几种:

l         内存中加载的数据量过于庞大,如一次从数据库取出过多数据;

l         集合类中有对对象的引用,使用完后未清空,使得JVM不能回收;

l         代码中存在死循环或循环产生过多重复的对象实体;

l         使用的第三方软件中的BUG;

l         启动参数内存值设定的过小;

3.内存溢出的解决
内存溢出虽然很棘手,但也有相应的解决办法,可以按照从易到难,一步步的解决。

第一步,就是修改JVM启动参数,直接增加内存。这一点看上去似乎很简单,但很容易被忽略。JVM默认可以使用的内存为64M,Tomcat默认可以使用的内存为128MB,对于稍复杂一点的系统就会不够用。在某项目中,就因为启动参数使用的默认值,经常报“OutOfMemory”错误。因此,-Xms,-Xmx参数一定不要忘记加。

第二步,检查错误日志,查看“OutOfMemory”错误前是否有其它异常或错误。在一个项目中,使用两个数据库连接,其中专用于发送短信的数据库连接使用DBCP连接池管理,用户为不将短信发出,有意将数据库连接用户名改错,使得日志中有许多数据库连接异常的日志,一段时间后,就出现“OutOfMemory”错误。经分析,这是由于DBCP连接池BUG引起的,数据库连接不上后,没有将连接释放,最终使得DBCP报“OutOfMemory”错误。经过修改正确数据库连接参数后,就没有再出现内存溢出的错误。

查看日志对于分析内存溢出是非常重要的,通过仔细查看日志,分析内存溢出前做过哪些操作,可以大致定位有问题的模块。

第三步,安排有经验的编程人员对代码进行走查和分析,找出可能发生内存溢出的位置。重点排查以下几点:

l         检查代码中是否有死循环或递归调用。

l         检查是否有大循环重复产生新对象实体。

l         检查对数据库查询中,是否有一次获得全部数据的查询。一般来说,如果一次取十万条记录到内存,就可能引起内存溢出。这个问题比较隐蔽,在上线前,数据库中数据较少,不容易出问题,上线后,数据库中数据多了,一次查询就有可能引起内存溢出。因此对于数据库查询尽量采用分页的方式查询。

l         检查List、MAP等集合对象是否有使用完后,未清除的问题。List、MAP等集合对象会始终存有对对象的引用,使得这些对象不能被GC回收。

第四步,使用内存查看工具动态查看内存使用情况。某个项目上线后,每次系统启动两天后,就会出现内存溢出的错误。这种情况一般是代码中出现了缓慢的内存泄漏,用上面三个步骤解决不了,这就需要使用内存查看工具了。

内存查看工具有许多,比较有名的有:Optimizeit Profiler、JProbe Profiler、JinSight和Java1.5的Jconsole等。它们的基本工作原理大同小异,都是监测Java程序运行时所有对象的申请、释放等动作,将内存管理的所有信息进行统计、分析、可视化。开发人员可以根据这些信息判断程序是否有内存泄漏问题。一般来说,一个正常的系统在其启动完成后其内存的占用量是基本稳定的,而不应该是无限制的增长的。持续地观察系统运行时使用的内存的大小,可以看到在内存使用监控窗口中是基本规则的锯齿形的图线,如果内存的大小持续地增长,则说明系统存在内存泄漏问题。通过间隔一段时间取一次内存快照,然后对内存快照中对象的使用与引用等信息进行比对与分析,可以找出是哪个类的对象在泄漏。

通过以上四个步骤的分析与处理,基本能处理内存溢出的问题。当然,在这些过程中也需要相当的经验与敏感度,需要在实际的开发与调试过程中不断积累。

总体上来说,产生内存溢出是由于代码写的不好造成的,因此提高代码的质量是最根本的解决办法。有的人认为先把功能实现,有BUG时再在测试阶段进行修正,这种想法是错误的。正如一件产品的质量是在生产制造的过程中决定的,而不是质量检测时决定的,软件的质量在设计与编码阶段就已经决定了,测试只是对软件质量的一个验证,因为测试不可能找出软件中所有的BUG。

 

--------------------------------------------------------------------------------------------------------------------------------

 

原因有很多种,比如:

1.数据量过于庞大;死循环 ;静态变量和静态方法过多;递归;无法确定是否被引用的对象;

2.虚拟机不回收内存(内存泄漏);

    说白了就是程序运行要用到的内存大于虚拟机能提供的最大内存就发生内存溢出了。 内存溢出的问题要看业务和系统大小而定,对于某些系统可能内存溢出不常见,但某些系统还是很常见的解决的方法,

一个是优化程序代码,如果业务庞大,逻辑复杂,尽量减少全局变量的引用,让程序使用完变量的时候释放该引用能够让垃圾回收器回收,释放资源。
二就是物理解决,增大物理内存,然后通过:-Xms256m -Xmx256m -XX:MaxNewSize=256m -XX:MaxPermSize=256m的修改

一、内存溢出类型
1 、 java.lang.OutOfMemoryError: PermGen space

JVM 管理两种类型的内存,堆和非堆。堆是给开发人员用的上面说的就是,是在 JVM 启动时创建;非堆是留给 JVM 自己用的,用来存放类的信息的。它和堆不同,运行期内 GC 不会释放空间。如果 web app 用了大量的第三方 jar 或者应用有太多的 class 文件而恰好 MaxPermSize 设置较小,超出了也会导致这块内存的占用过多造成溢出,或者 tomcat 热部署时侯不会清理前面加载的环境,只会将 context 更改为新部署的,非堆存的内容就会越来越多。

2 、 java.lang.OutOfMemoryError: Java heap space

第一种情况是个补充,主要存在问题就是出现在这个情况中。其默认空间 ( 即 -Xms) 是物理内存的 1/64 ,最大空间 (-Xmx) 是物理内存的 1/4 。如果内存剩余不到 40 %, JVM 就会增大堆到 Xmx 设置的值,内存剩余超过 70 %, JVM 就会减小堆到 Xms 设置的值。所以服务器的 Xmx 和 Xms 设置一般应该设置相同避免每次 GC 后都要调整虚拟机堆的大小。假设物理内存无限大,那么 JVM 内存的最大值跟操作系统有关,一般 32 位机是 1.5g 到 3g 之间,而 64 位的就不会有限制了。

注意:如果 Xms 超过了 Xmx 值,或者堆最大值和非堆最大值的总和超过了物理内存或者操作系统的最大限制都会引起服务器启动不起来。

垃圾回收 GC 的角色

JVM 调用 GC 的频度还是很高的,主要两种情况下进行垃圾回收:

当应用程序线程空闲;另一个是 java 内存堆不足时,会不断调用 GC ,若连续回收都解决不了内存堆不足的问题时,就会报 out of memory 错误。因为这个异常根据系统运行环境决定,所以无法预期它何时出现。

根据 GC 的机制,程序的运行会引起系统运行环境的变化,增加 GC 的触发机会。

为了避免这些问题,程序的设计和编写就应避免垃圾对象的内存占用和 GC 的开销。显示调用 System.GC() 只能建议 JVM 需要在内存中对垃圾对象进行回收,但不是必须马上回收,

一个是并不能解决内存资源耗空的局面,另外也会增加 GC 的消耗。

二、 JVM 内存区域组成
简单的说 java中的堆和栈

java把内存分两种:一种是栈内存,另一种是堆内存

1。在函数中定义的基本类型变量和对象的引用变量都在函数的栈内存中分配;

2。堆内存用来存放由 new创建的对象和数组

在函数(代码块)中定义一个变量时, java就在栈中为这个变量分配内存空间,当超过变量的作用域后, java会自动释放掉为该变量所分配的内存空间;在堆中分配的内存由 java虚拟机的自动垃圾回收器来管理

堆的优势是可以动态分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的。缺点就是要在运行时动态分配内存,存取速度较慢;

栈的优势是存取速度比堆要快,缺点是存在栈中的数据大小与生存期必须是确定的无灵活 性。

java 堆分为三个区: New 、 Old 和 Permanent

GC 有两个线程:

新创建的对象被分配到 New 区,当该区被填满时会被 GC 辅助线程移到 Old 区,当 Old 区也填满了会触发 GC 主线程遍历堆内存里的所有对象。 Old 区的大小等于 Xmx 减去 -Xmn

java栈存放

栈调整:参数有 +UseDefaultStackSize -Xss256K,表示每个线程可申请 256k的栈空间

每个线程都有他自己的 Stack

三、 JVM如何设置虚拟内存
提示:在 JVM中如果 98%的时间是用于 GC且可用的 Heap size 不足 2%的时候将抛出此异常信息。

提示: Heap Size 最大不要超过可用物理内存的 80%,一般的要将 -Xms和 -Xmx选项设置为相同,而 -Xmn为 1/4的 -Xmx值。

提示: JVM初始分配的内存由 -Xms指定,默认是物理内存的 1/64; JVM最大分配的内存由 -Xmx指定,默认是物理内存的 1/4。

默认空余堆内存小于 40%时, JVM就会增大堆直到 -Xmx的最大限制;空余堆内存大于 70%时, JVM会减少堆直到 -Xms的最小限制。因此服务器一般设置 -Xms、 -Xmx相等以避免在每次 GC 后调整堆的大小。

提示:假设物理内存无限大的话, JVM内存的最大值跟操作系统有很大的关系。

简单的说就 32位处理器虽然可控内存空间有 4GB,但是具体的操作系统会给一个限制,

这个限制一般是 2GB-3GB(一般来说 Windows系统下为 1.5G-2G, Linux系统下为 2G-3G), 而 64bit以上的处理器就不会有限制了

提示:注意:如果 Xms超过了 Xmx值,或者堆最大值和非堆最大值的总和超过了物理内 存或者操作系统的最大限制都会引起服务器启动不起来。

提示:设置 NewSize、 MaxNewSize相等, “new”的大小最好不要大于 “old”的一半,原因是 old区如果不够大会频繁的触发 “主 ” GC ,大大降低了性能

JVM使用 -XX:PermSize设置非堆内存初始值,默认是物理内存的 1/64;

由 XX:MaxPermSize设置最大非堆内存的大小,默认是物理内存的 1/4。

解决方法:手动设置 Heap size

修改 TOMCAT_HOME/bin/catalina.bat

在“ echo “Using CATALINA_BASE: $CATALINA_BASE””上面加入以下行:

  1. JAVA_OPTS=”-server -Xms800m -Xmx800m -XX:MaxNewSize=256m”   

四、性能检查工具使用
定位内存泄漏:

JProfiler 工具主要用于检查和跟踪系统(限于 Java 开发的)的性能。 JProfiler 可以通过时时的监控系统的内存使用情况,随时监视垃圾回收,线程运行状况等手段,从而很好的监视 JVM 运行情况及其性能。


1. 应用服务器内存长期不合理占用,内存经常处于高位占用,很难回收到低位;

2. 应用服务器极为不稳定,几乎每两天重新启动一次,有时甚至每天重新启动一次;

3. 应用服务器经常做 Full GC(Garbage Collection),而且时间很长,大约需要 30-40秒,应用服务器在做 Full GC的时候是不响应客户的交易请求的,非常影响系统性能。

因为开发环境和产品环境会有不同,导致该问题发生有时会在产品环境中发生, 通常可以使用工具跟踪系统的内存使用情况,在有些个别情况下或许某个时刻确实 是使用了大量内存导致 out of memory,这时应继续跟踪看接下来是否会有下降,

如果一直居高不下这肯定就因为程序的原因导致内存泄漏。

五、不健壮代码的特征及解决办法
1 、尽早释放无用对象的引用。好的办法是使用临时变量的时候,让引用变量在退出活动域后,自动设置为 null ,暗示垃圾收集器来收集该对象,防止发生内存泄露。

对于仍然有指针指向的实例, jvm 就不会回收该资源 , 因为垃圾回收会将值为 null 的对象作为垃圾,提高 GC 回收机制效率;

2 、我们的程序里不可避免大量使用字符串处理,避免使用 String ,应大量使用 StringBuffer ,每一个 String 对象都得独立占用内存一块区域;

  1. String str = “aaa”;   
  2.   
  3. String str2 = “bbb”;   
  4.   
  5. String str3 = str + str2;// 假如执行此次之后 str ,str2 以后再不被调用 , 那它就会被放在内存中等待 Java 的 gc 去回收 , 程序内过多的出现这样的情况就会报上面的那个错误 , 建议在使用字符串时能使用 StringBuffer 就不要用 String, 这样可以省不少开销;   

3 、尽量少用静态变量,因为静态变量是全局的, GC 不会回收的;

4 、避免集中创建对象尤其是大对象, JVM 会突然需要大量内存,这时必然会触发 GC 优化系统内存环境;显示的声明数组空间,而且申请数量还极大。

这是一个案例想定供大家警戒:

使用jspsmartUpload作文件上传,现在运行过程中经常出现java.outofMemoryError的错误,用top命令看看进程使用情况,发现内存不足2M,花了很长时间,发现是jspsmartupload的问题。把jspsmartupload组件的源码文件(class文件)反编译成Java文件,如梦方醒:

  1. m_totalBytes = m_request.getContentLength();        
  2. m_binArray = new byte[m_totalBytes];      

变量m_totalBytes表示用户上传的文件的总长度,这是一个很大的数。如果用这样大的数去声明一个byte数组,并给数组的每个元素分配内存空间,而且m_binArray数组不能马上被释放,JVM的垃圾回收确实有问题,导致的结果就是内存溢出。

jspsmartUpload为什末要这样作,有他的原因,根据RFC1867的http上传标准,得到一个文件流,并不知道文件流的长度。设计者如果想文件的长度,只有操作servletinputstream一次才知道,因为任何流都不知道大小。只有知道文件长度了,才可以限制用户上传文件的长度。为了省去这个麻烦,jspsmartUpload设计者直接在内存中打开文件,判断长度是否符合标准,符合就写到服务器的硬盘。这样产生内存溢出,这只是我的一个猜测而已。

所以编程的时候,不要在内存中申请大的空间,因为web服务器的内存有限,并且尽可能的使用流操作,例如

  1. byte[] mFileBody = new byte[512];   
  2.          Blob vField= rs.getBlob("FileBody");   
  3.       InputStream instream=vField.getBinaryStream();   
  4.       FileOutputStream fos=new FileOutputStream(saveFilePath+CFILENAME);   
  5.          int b;   
  6.                       while( (b =instream.read(mFileBody)) != -1){   
  7.                         fos.write(mFileBody,0,b);   
  8.                          }   
  9.         fos.close();   
  10.       instream.close();  

5 、尽量运用对象池技术以提高系统性能;生命周期长的对象拥有生命周期短的对象时容易引发内存泄漏,例如大集合对象拥有大数据量的业务对象的时候,可以考虑分块进行处理,然后解决一块释放一块的策略。

6 、不要在经常调用的方法中创建对象,尤其是忌讳在循环中创建对象。可以适当的使用 hashtable , vector 创建一组对象容器,然后从容器中去取那些对象,而不用每次 new 之后又丢弃

7 、一般都是发生在开启大型文件或跟数据库一次拿了太多的数据,造成 Out Of Memory Error 的状况,这时就大概要计算一下数据量的最大值是多少,并且设定所需最小及最大的内存空间值。

posted @ 2012-10-25 23:16 abin 阅读(626) | 评论 (0)编辑 收藏

在hibernate中,用hql语句查询实体类,采用list方法的返回结果为一个List,该List中封装的对象分为以下三种情况:
1.查询全部字段的情况下,如"from 实体类",list中封装的对象为实体类本身,各属性都将得到填充。
2.只查询一个字段,默认情况下,list中封装的是Object对象。
3.查询两个或两个以上的字段,默认情况下,list中封装的是Object[],长度与所查询的字段数一致。

对于后两种情况,用标签遍历时不太方便,因为无法直接转换成实体类的对象。比较简单的解决方法是:

の:在hql中使用select new 包名.类名(属性1,属性2……) from 实体类,同时在实体类中添加带参的构造方法,参数的个数和顺序与(属性1,属性2……) 保持一致,这样我们得到的list中存放的依然是实体类的对象,所查询到的属性得到了填充,使用起来更为方便。

  の:hql查询多表部分字段,select new 包名.表1实体类名(表1.属性1,表2.属性2……) from 表1实体类,表2实体类 where 表1.ID=表2.ID(即相关联的字段),同时在要返回的表1实体类中添加表2的属性和带参的构造方法,参数的个数和顺序与(表1.属性1,表2.属性 2……) 保持一致

例如要查询Problem 中的pid,score,title,totalAccept,totalSubmission,unSee

public class Problem {  
    private int pid;  
    private int score;  
    private int timeLimit;  
    private int memoryLimit;  
    private int totalAccept;  
    private int totalSubmission;  
    private int unSee;  
    private String title;  
    private String description;  
    private String input;  
    private String output;  
      
    public Problem(int pid, int score,String title, int totalAccept, int totalSubmission,  
             int unSee) {  
        super();  
        this.pid = pid;  
        this.score = score;  
        this.totalAccept = totalAccept;  
        this.totalSubmission = totalSubmission;  
        this.unSee = unSee;  
        this.title = title;  
    }  
    //省略getter 和 setter   
}  
查询语句如下
      Query query=session.createQuery("select new Problem(pid,score,title,totalAccept,totalSubmission,unSee) from Problem order by pid");  
        //query.setFirstResult(firstResult); //分页函数   
        //query.setMaxResults(maxResutl);   
      
        List<Problem> problems=query.list();//返回的还是Problem对象 









关于hibernate的问题: 
我现在有条 
hql="select s.id,s.name,t.id,t.name from User s,Useraddress t where t.id=s.id" 

这条sql里面的User和Useraddress是两个实体类,现在组合查询分别取出来两个实体类里面的两个字段,然后我想再建立一个实体类Result,里面定义这四个结果集里面的字段,能不能执行完这条hql,正好把这个结果集对应到实体类Result里面呢,Result这个实体类,没写映射文件Result.hbm.xml. 
希望能帮下忙 

2种做法 
创建一个class temp 
有属性sid,name,tid,sname,tname 
创建一个构造函数 
public temp(sid,name,tid,sname,tname) 



1.hql中 
List<temp> 

select new temp(s.id,s.name,t.id,t.name) from User s,Useraddress t where t.id=s.id 

2.List 
记录的每一行是object[] 遍历 
object[0] ==s.id 
object[1] ==s.name 
object[2] ==t.id 
object[3] ==t.name 

 



感谢glamey兄弟的文章,正好解决了当前遇到的问题。原文链接如下:http://glamey.iteye.com/blog/721019
        假设我们现在有一个DTO,其属性包括两张表的属性,我们现在需要将sql语句查询得到的内容转为一个DTO对象,其解决方法如下:  

String sql = "select u.userName as userName ,p.title as title ,p.addTime as addTime from user as u,post as p where u.id=p.userId"  
Query q = factory.getCurrentSession().createSQLQuery(sql).setResultTransformer(Transformers.aliasToBean(PostVO.class));

      上面select中as后面的内容必须和PostVO中属性名一致,这样就可以返回一个针对PostVO的一个集合。 
        其实大家可以看下hibernate这一部分的源码就会发现,主要是使用了AliasToBeanResultTransformer这个类,通过sql的查询,会返回数组,然后hibernate根据数据表的映射,自动帮我们来set对应的字段属性,所以标红的部分务必要跟VO中的属性值一直,要不然会报错的。 
        如果需要的话,大家也可以重写这个类。例如VOResultTransformer。然后在dao中更改成:  

setResultTransformer(new VOResultTransformer(PostVO.class));

  另外,除了以上glamey的方法外,还有一种方法:  
Query q = session.createQuery("select new com.hibernate.MsgInfo(m.id, m.cont, m.topic.title, m.topic.category.name) from Msg m");
List<MsgInfo> list=q.list();

     其中,MsgInfo是DTO。值得注意的是,第二种方法中DTO必须提供带参数的构造方法,并且HQL语句中属性的位置要与构造方法中的位置一一对应。 
posted @ 2012-10-25 14:32 abin 阅读(21318) | 评论 (4)编辑 收藏

package net.abin.lee.basic;

public class Can implements Cloneable{
 private int id;
 private String address;
 public Can() {
 }
 public Can(int id, String address) {
  super();
  this.id = id;
  this.address = address;
 }
 public Object clone()throws CloneNotSupportedException{
  return super.clone();
 }
 public int hashCode(){
  final int prime=31;
  int result=1;
  result=prime*result+id;
  result=prime*result+((address==null?0:address.hashCode()));
  return result;
 }
 public int getId() {
  return id;
 }
 public void setId(int id) {
  this.id = id;
 }
 public String getAddress() {
  return address;
 }
 public void setAddress(String address) {
  this.address = address;
 }
 
}










package net.abin.lee.basic;

import junit.framework.TestCase;

public class UserTest extends TestCase{
 public void test1() throws CloneNotSupportedException{
  User user1=new User("12","abin",3);
  User user2=user1;
  User user3=(User)user1.clone();
  System.out.println("user1=user2 :"+(user1==user2));
  System.out.println("user1equalsuser2 :"+(user1.equals(user2)));
  
  System.out.println("user1=user3 :"+(user1==user3));
  System.out.println("user1equalsuser3 :"+(user1.equals(user3)));
  
 }
 @Override
 protected void runTest() throws Throwable {
  System.out.println("55");
  super.runTest();
 }
}

posted @ 2012-10-24 13:27 abin 阅读(412) | 评论 (0)编辑 收藏

仅列出标题
共50页: First 上一页 23 24 25 26 27 28 29 30 31 下一页 Last