mysql ip address convert (ip2bigint,bigint2ip)

Convert IP address  to bigint





CREATE FUNCTION `F_Ip2Int`(ip varchar(15)) RETURNS bigint(20)
BEGIN
  declare tmp bigint default 0;
  while instr(ip,’.’)>0 do
    set tmp = tmp*256+ left(ip,instr(ip,’.’)-1);
    set ip = right(ip,length(ip)-instr(ip,’.’));
  end while;
  set tmp = tmp*256+ip;
  return tmp;
END

Convert bigint to IP Address




CREATE FUNCTION `F_Int2Ip`(iip bigint) RETURNS varchar(15)
BEGIN

  return concat((iip & 0xFF000000)>>24, ‘.’,
                (iip & 0x00FF0000)>>16, ‘.’,
                (iip & 0x0000FF00)>>8, ‘.’,
                iip & 0x000000FF);

END


proxool.FatalSqlExceptionHelper.testException()

我终于找到了出问题的线程了。


通过thread dump 我发现如下线程一直在运行:
“resin-tcp-connection-*:80-6075” daemon prio=1 tid=0x0857aac8 nid=0x7fb0 runnable [0x82dfe000..0x82dff19c]
at org.logicalcobwebs.proxool.FatalSqlExceptionHelper.testException(FatalSqlExceptionHelper.java:116)
at org.logicalcobwebs.proxool.FatalSqlExceptionHelper.testException(FatalSqlExceptionHelper.java:103)
at org.logicalcobwebs.proxool.AbstractProxyStatement.testException(AbstractProxyStatement.java:65)
at org.logicalcobwebs.proxool.ProxyStatement.invoke(ProxyStatement.java:146)
at org.logicalcobwebs.proxool.ProxyStatement.intercept(ProxyStatement.java:57)
at $java.sql.Statement$$EnhancerByCGLIB$$1a91e2dc.close()
at com.tag.db.doEndTag(valuetag.java:438)
at _jsp._rst._eng_0aa__jsp._jspService(_products_0viewinfo__jsp.java:75)
at com.caucho.jsp.JavaPage.service(JavaPage.java:60)
at com.caucho.jsp.Page.pageservice(Page.java:570)
at com.caucho.server.dispatch.PageFilterChain.doFilter(PageFilterChain.java:159)
at com.kenfor.exutil.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:152)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:70)
at com.kenfor.exutil.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:152)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:70)
at com.caucho.server.webapp.WebAppFilterChain.doFilter(WebAppFilterChain.java:178)
at com.caucho.server.dispatch.ServletInvocation.service(ServletInvocation.java:229)
at com.caucho.server.http.HttpRequest.handleRequest(HttpRequest.java:267)
at com.caucho.server.port.TcpConnection.run(TcpConnection.java:388)
– locked <0x5c472008> (a java.lang.Object)
at com.caucho.util.ThreadPool.runTasks(ThreadPool.java:490)
at com.caucho.util.ThreadPool.run(ThreadPool.java:423)
at java.lang.Thread.run(Thread.java:595)


然后我又查看了顶级的代码调用
at org.logicalcobwebs.proxool.FatalSqlExceptionHelper.testException(FatalSqlExceptionHelper.java:116)
也就是testException这个方法一直在执行,我不清楚为什么为会出现如此死循环。


我想问问大家,什么样的代码会导致proxool的testException一直运行着。



——————————————————————————–


不知道是分数不够,还是人才稀少,怎么就没人回答呢。郁闷


——————————————————————————–


为什么会重复出现:
at com.kenfor.exutil.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:152)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:70)
at com.kenfor.exutil.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:152)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:70)
谁能告诉我啊。


——————————————————————————–


本来proxool是很有口碑的连接池 ,怎么会导致


at org.logicalcobwebs.proxool.FatalSqlExceptionHelper.testException(FatalSqlExceptionHelper.java:116)中testException运行没完没了呢。


——————————————————————————–


努力接分升级中…帮你up!


——————————————————————————–


filter 死循环调用?


——————————————————————————–


回复:iihero(阿黑哥)


应该不是filter的引起的,如果是filter的话,那所有的页面都会很容易进入死循环。


——————————————————————————–


下面就是这个永远不结束的方法,我看了一下源代码,虽然有循环部分,但也不导致死循环,
大伙帮我分析一下,具体是什么原因会导致下面的代码一直执行?
/**
* Test to see if an exception is a fatal one
* @param cpd the definition so we can find out what a fatal exception looks like
* @param t the exception to test
* @param level the recursion level (max 20)
* @return true if it is fatal
*/
protected static boolean testException(ConnectionPoolDefinitionIF cpd, Throwable t, int level) {
boolean fatalSqlExceptionDetected = false;
Iterator i = cpd.getFatalSqlExceptions().iterator();
while (i.hasNext()) {
if (t.getMessage() != null && t.getMessage().indexOf((String) i.next()) > -1) {
// This SQL exception indicates a fatal problem with this connection.
fatalSqlExceptionDetected = true;
}
}


// If it isn’t fatal, then try testing the contained exception
if (!fatalSqlExceptionDetected && level < 20) {
Throwable cause = getCause(t);
if (cause != null) {
fatalSqlExceptionDetected = testException(cpd, cause, level + 1);
}
}


return fatalSqlExceptionDetected;
}


——————————————————————————–


while (i.hasNext()) {
if (t.getMessage() != null && t.getMessage().indexOf((String) i.next()) > -1) {
// This SQL exception indicates a fatal problem with this connection.
fatalSqlExceptionDetected = true;
}
}


t.getMessage() != null这句话不成立的话,就没机会调用i.next()
就死循环了。


——————————————————————————–


在网上大家都对proxool赞赏有加,但是我们的项目出现如此严重的错误,实属不应该,
请兄弟们帮我查明此原因,不让我再去怀疑proxool的过错了,把清白留proxool。


——————————————————————————–


回复:zhmt(不爽你就用分砸我!!!)


t.getMessage() != null不成立,也应该会再次调用i.hasNext()吧


——————————————————————————–


请大伙帮我把铁顶起来,都快两天了,还是没找到答案。


——————————————————————————–


你说的错了,&& 运算是从左到右,左边的不成立,直接就返回false了,不再计算右边的。所以不调用i.next()。


楼主要加强基础。


——————————————————————————–


你可以写个小例子测试一下。


——————————————————————————–


当 t.getMessage() != null不成立时,是“t.getMessage().indexOf((String) i.next()) > -1”没机会执行。不是i.hasNext


——————————————————————————–


回复: zhmt(不爽你就用分砸我!!!)


我还是不明白,t.getMessage() != null这句话不成立的话,就会导致死循环。


——————————————————————————–


就算“t.getMessage().indexOf((String) i.next()) > -1不知道,也不会导致死循环啊。


——————————————————————————–


我上面的那段代码是从proxool中取出来的,如果这么容易就死循环了,那我就要怀疑这个东西的安全性啦。


——————————————————————————–


你的问题的背景是什么啊?
不能光看这一点。


——————————————————————————–


resin-tcp-connection-*:80-6075″ daemon prio=1 tid=0x0857aac8 nid=0x7fb0 runnable


这是个守护线程,(daemon),一直运行的话,是很正常的。可能问题不在这里,你的是什么性能问题啊?


——————————————————————————–


好,那我就说说背景 :


我维护的是个网站项目,网站经常服务器cpu 99%,并且上去了就不下来了,开始我就确定是
死循环的问题,但是找不到根据,前两天我用kill -3 pid,每隔5分钟Thread Dump一下,发现
上面的线程一直在虚拟机(JVM)里面运行者。那只有死循环才不会退出的。
我不知道我讲清楚没?


——————————————————————————–


daemon是守护进程,但是不应该不结束。


——————————————————————————–


你确信是这个线程启动后cpu才到100%的吗?


——————————————————————————–


是的。在平时,我找不到这样的线程。


——————————————————————————–


我查了一下它的源码,这个类是用来检查一个异常是否是严重异常,它能一直运行说明你的应用导致了很多sql异常。如果这个pool是经过大家的检验的话,可能你的应用中,哪一部分的sql调用很有问题。


——————————————————————————–


是的,但是很多异常也会有个数量限制啊,可能处理校验的速度慢啊,而不会出现,死循环啊。
在页面上传入的sql语句难免有些问题,我测试过,一般情况下,系统会自动处理的,但是我想在就不明白,什么情况下,什么样的SQL语句会导致死循环。


——————————————————————————–


你看了有多少个这样线程了吗?
可能不是死循环,而是线程结束后又被启动起来。或者是启动了多个这样的线程。
如果不是我感才说的那个死循环的,就不可能出现死循环了(next和hasNext要成对使用才不会死在那,如果只使用hasNext而不使用next,那么iterator是不往下走的,就会死了。)。
另外它的递归调用也不会超过20层,所以也不会死。


——————————————————————————–


我觉得从自己的应用上来改进应该更好。


——————————————————————————–


回复:zhmt(不爽你就用分砸我!!!)


你说的有道理,如果 t.getMessage() ==null的话,就会陷入死循环。


但是我看我们的代码都是按照JDBC规范来写的啊。


下面我贴些原码,帮我看看有什么问题。


 


——————————————————————————–


public HashMap getdbValue(PoolBean pool) throws Exception
{
if(pool.getLog().isDebugEnabled())
pool.getLog().debug(“star getdbValue”);


String system_name = pool.getDatabaseInfo().getSystemName();
HashMap result = null;
String temp_sql = createSql();
if(temp_sql == null)
throw new SQLException(“not sql statement”);


Statement stmt = null;
ResultSet rs = null;
Connection con = null;
try
{
con = pool.getNoInfoConnection();// .getConnection();
con.setReadOnly(true);
stmt = con.createStatement();
rs = stmt.executeQuery(temp_sql);
// rs = stmt.executeQuery(sql);
if (rs != null) {
ResultSetMetaData rsmd = rs.getMetaData();
int colCount = rsmd.getColumnCount();
if (rs.next()) {
result = new HashMap();
for (int i = 1; i <= colCount; i++) {
String name = rsmd.getColumnName(i);
name = name.toLowerCase();
String type_name = rsmd.getColumnTypeName(i).toLowerCase();
// System.out.println(“field name : ” + name + ” , type_anme : ” + type_name);
if (“text”.equals(type_name)) {
//当字段类型为text时,如果直接用rs.getObject(i)取数据,在jtds1.0版本中不能直接取出,改为以下方式即可 2005-07-22 张贵平
String tt_str = rs.getString(i);
// System.out.println(“text — “+tt_str);
if (tt_str == null)
tt_str = “”;
else
tt_str = tt_str.trim();
result.put(name.trim(), tt_str);
}
else {
Object obj_value = rs.getObject(i);
if (obj_value instanceof java.lang.String) {
String t_str = null;
if (obj_value == null)
t_str = “”;
else
t_str = String.valueOf(obj_value).trim();
result.put(name.trim(), t_str);
}
else {
result.put(name.trim(), obj_value);
}
}
}
}
rsmd = null;
}
rs.close();
stmt.close();
con.setReadOnly(false);
con.close();
}
catch(SQLException e)
{
//CloseCon.Close(con);
pool.getLog().error(system_name+”,”+e.getMessage()+”,sql:”+temp_sql);
throw new SQLException(“database perform error : ” + e.getMessage());
}
finally
{
CloseCon.Close(con);
}


return result;


}


从线程堆栈上看$java.sql.Statement$$EnhancerByCGLIB$$1a91e2dc.close()
,是从stmt.close()进去的。



——————————————————————————–


觉得不规范
rs.close();
stmt.close();
con.setReadOnly(false);
con.close();


以上这些东西都要放在finnally块中的。


我没用过PoolBean,不知道怎么用,觉得数据库的操作好像没多大问题。你倒网上搜索资料看看吧。


——————————————————————————–


你看下Filter里面的跳转是不是错了。


——————————————————————————–


回复:zhmt(不爽你就用分砸我!!!)


PoolBean 是我们自己写的一个类,主要是做跟连接池的衔接工作。


是的,不是很规范,但是这样也应该不会导致proxool死循环。


——————————————————————————–


我们自己的Filter类,看看有什么问题。


public class SetCharacterEncodingFilter implements Filter {


Log log = LogFactory.getLog(this.getClass().getName());


// —————————————————– Instance Variables


/**
* The default character encoding to set for requests that pass through
* this filter.
*/
protected String encoding = null;



/**
* The filter configuration object we are associated with. If this value
* is null, this filter instance is not currently configured.
*/
protected FilterConfig filterConfig = null;


/**
* 上传文件的最大大小
*/
protected int fileMaxLength = 200*1024; //200K


/**
* Should a character encoding specified by the client be ignored?
*/
protected boolean ignore = true;



/**
* Take this filter out of service.
*/
public void destroy() {


this.encoding = null;
this.filterConfig = null;


}



/**
* Select and set (if specified) the character encoding to be used to
* interpret request parameters for this request.
*
* @param request The servlet request we are processing
* @param result The servlet response we are creating
* @param chain The filter chain we are processing
*
* @exception IOException if an input/output error occurs
* @exception ServletException if a servlet error occurs
*/
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException {


// Conditionally select and set the character encoding to be used


HttpServletRequest t_re = (HttpServletRequest) request;


String re_uri = trimString(t_re.getRequestURI());
String re_host = trimString(t_re.getServerName());
String qu_str = trimString(t_re.getQueryString());



if (re_uri.indexOf(“.do”) > 0)
{
if (log.isInfoEnabled())
log.info(re_host + re_uri + “?” + qu_str);


try
{


if (ignore || (request.getCharacterEncoding() == null)) {
String encoding = selectEncoding(request);
if (encoding != null)
request.setCharacterEncoding(encoding);
}
// Pass control on to the next filter
chain.doFilter(request, response);
}
catch(Exception e)
{
// e.printStackTrace();
String error_mes = e.getMessage();
String strServerName = null;
String strQueryString = null;
String requestUrl = null;
String remoteAddr = null;
String referer = “”;
if(error_mes.indexOf(“reset”)<0 )
{
try {
strServerName = t_re.getServerName();
strQueryString = t_re.getQueryString();
requestUrl = t_re.getRequestURI();
// strQueryString = CodeTransfer.ISOToUnicode(strQueryString);
referer = t_re.getHeader(“referer”);
remoteAddr = t_re.getRemoteAddr();
}
catch (Exception e1) {}
if (error_mes != null && !”null”.equals(error_mes)&& error_mes.length() > 0) {
log.error(“,exception:” +
error_mes + strServerName + ” , ” + strQueryString + ” , ” +
requestUrl + ” , ” + referer);
// System.out.println(“exception at filter:” +
// error_mes);
}


}
if(log.isInfoEnabled())
log.info(strServerName + ” , ” + strQueryString+ ” , ” + requestUrl + ” , ” + referer);
}


}



/**
* Place this filter into service.
*
* @param filterConfig The filter configuration object
*/
public void init(FilterConfig filterConfig) throws ServletException {


this.filterConfig = filterConfig;
this.encoding = filterConfig.getInitParameter(“encoding”);
String value = filterConfig.getInitParameter(“ignore”);
String file_max_length = filterConfig.getInitParameter(“file_max_length”);
if(file_max_length!=null && file_max_length.length() >0)
{
fileMaxLength = com.kenfor.util.MyUtil.getStringToInt(file_max_length,200)*1024;
}


if (value == null)
this.ignore = true;
else if (value.equalsIgnoreCase(“true”))
this.ignore = true;
else if (value.equalsIgnoreCase(“yes”))
this.ignore = true;
else
this.ignore = false;


}


/**
* Select an appropriate character encoding to be used, based on the
* characteristics of the current request and/or filter initialization
* parameters. If no character encoding should be set, return
* null.
*


* The default implementation unconditionally returns the value configured
* by the encoding initialization parameter for this
* filter.
*
* @param request The servlet request we are processing
*/
protected String selectEncoding(ServletRequest request) {


return (this.encoding);


}
private String trimString(String value)
{
String result = “”;
if(value !=null)
result = value.trim();


return result;
}



}


 


 


——————————————————————————–


如果真的是proxool,那我应该感到欣慰,如果是我们写的代码不当引起的,但我就真的无地之容了。


——————————————————————————–


呵呵,这个我也搞不清楚,楼主最好把你们的那个poolBean自己测试一下。
能找到那种情况下出那个错误是最好的。


看看循环使用的时候是否也抛出这个异常,如果这样的话就查查哪的问题吧。如果不出错,可能就是sql写的有问题了。


Java on Guice

Java on Guice
Guice 1.0 User’s Guide






Guice (pronounced “juice”) is an ultra-lightweight, next-generation dependency injection container for Java 5 and later.


Introduction


The enterprise Java community exerts a lot of effort toward wiring objects together. How does your web application get access to a middle tier service, or your service to the logged in user or transaction manager? You’ll find many general and specific solutions to this problem. Some rely on patterns. Others use frameworks. All result in varying degrees of testability and some amount of boilerplate code. You’ll soon see that Guice enables the best of all worlds: easy unit testing, maximal flexibility and maintainability, and minimal repetition.



We’ll use an unrealistically simple example to illustrate the benefits of Guice over some classic approaches which you’re probably already familiar with. The following example is so simple in fact that, even though it will show immediate benefits, we won’t actually do Guice justice. We hope you’ll see that as your application grows, Guice’s benefits accelerate.



In this example, a client depends on a service interface. This could be any arbitrary service. We’ll just call it Service.




public interface Service {


  void go();
}



We have a default implementation of this service which the client should not depend directly on. If we decide to use a different service implementation in the future, we don’t want to go around and change all of our clients.




public class ServiceImpl implements Service {


  public void go() {


    …


  }


}



We also have a mock service which we can use in unit tests.



public class MockService implements Service {




  private boolean gone = false;

  public void go() {
    gone = true;
  }

  public boolean isGone() {
    return gone;
  }
}


Plain Old Factories


Before we discovered dependency injection, we mostly used the factory pattern. In addition to the service interface, you have a service factory which provides the service to clients as well as a way for tests to pass in a mock service. We’ll make the service a singleton so we can keep this example as simple as possible.


public class ServiceFactory {

  private ServiceFactory() {}
   
  private static Service instance = new ServiceImpl();

  public static Service getInstance() {
    return instance;
  }
 
  public static void setInstance(Service service) {
    instance = service;
  }
}


Our client goes directly to the factory every time it needs a service.



public class Client {

  public void go() {
    Service service = ServiceFactory.getInstance();
    service.go();
  }
}



The client is simple enough, but the unit test for the client has to pass in a mock service and then remember to clean up afterwards. This isn’t such a big deal in our simple example, but as you add more clients and services, all this mocking and cleaning up creates friction for unit test writing. Also, if you forget to clean up after your test, other tests may succeed or fail when they shouldn’t. Even worse, tests may fail depending on which order you run them in.



public void testClient() {
  Service previous = ServiceFactory.getInstance();
  try {
    final MockService mock = new MockService();
    ServiceFactory.setInstance(mock);
    Client client = new Client();
    client.go();
    assertTrue(mock.isGone());
  }
  finally {
    ServiceFactory.setInstance(previous);
  }
}




Finally, note that the service factory’s API ties us to a singleton approach. Even if getInstance() could return multiple instances, setInstance() ties our hands. Moving to a non-singleton implementation would mean switching to a more complex API.


Dependency Injection By Hand


The dependency injection pattern aims in part to make unit testing easier. We don’t necessarily need a specialized framework to practice dependency injection. You can get roughly 80% of the benefit writing code by hand.

While the client asked the factory for a service in our previous example, with dependency injection, the client expects to have its dependency passed in. Don’t call me, I’ll call you, so to speak.


public class Client {
   
  private final Service service;

  public Client(Service service) {
    this.service = service;
  }

  public void go() {
    service.go();
  }
}


This simplifies our unit test considerably. We can just pass in a mock service and throw everything away when we’re done.



public void testClient() {
  MockService mock = new MockService();
  Client client = new Client(mock);
  client.go();
  assertTrue(mock.isGone());
}


We can also tell from the API exactly what the client depends on.

Now, how do we connect the client with a service? When implementing dependency injection by hand, we can move all dependency logic into factory classes. This means we need a factory for our client, too.



public static class ClientFactory {

  private ClientFactory() {}

  public static Client getInstance() {
    Service service = ServiceFactory.getInstance();
    return new Client(service);
  }
}


Implementing dependency injection by hand requires roughly the same number of lines of code as plain old factories.

Dependency Injection with Guice


Writing factories and dependency injection logic by hand for every service and client can become tedious. Some other dependency injection frameworks even require you to explicitly map services to the places where you want them injected.

Guice aims to eliminate all of this boilerplate without sacrificing maintainability.

With Guice, you implement modules. Guice passes a binder to your module, and your module uses the binder to map interfaces to implementations. The following module tells Guice to map Service to ServiceImpl in singleton scope:


public class MyModule implements Module {
  public void configure(Binder binder) {
    binder.bind(Service.class)
      .to(ServiceImpl.class)
      .in(Scopes.SINGLETON);
  }
}


A module tells Guice what we want to inject. Now, how do we tell Guice where we want it injected? With Guice, you annotate constructors, methods and fields with @Inject.



public class Client {

  private final Service service;

  @Inject
  public Client(Service service) {
    this.service = service;
  }

  public void go() {
    service.go();
  }
}


The @Inject annotation makes it clear to a programmer editing your class which members are injected.

For Guice to inject Client, we must either directly ask Guice to create a Client instance for us, or some other class must have Client injected into it.

Guice vs. Dependency Injection By Hand


As you can see, Guice saves you from having to write factory classes. You don’t have to write explicit code wiring clients to their dependencies. If you forget to provide a dependency, Guice fails at startup. Guice handles circular dependencies automatically.

Guice enables you to specify scopes declaratively. For example, you don’t have to write the same code to store an object in the HttpSession over and over.

In the real world, you often don’t know an implementation class until runtime. You need meta factories or service locators for your factories. Guice addresses these problems with minimal effort.

When injecting dependencies by hand, you can easily slip back into old habits and introduce direct dependencies, especially if you’re new to the concept of dependency injection. Using Guice turns the tables and makes doing the right thing easier. Guice helps keep you on track.

More Annotations


When possible, Guice enables you to use annotations in lieu of explicit bindings and eliminate even more boilerplate code. Back to our example, if you need an interface to simplify unit testing but you don’t care about compile time dependencies, you can point to a default implementation directly from your interface.


@ImplementedBy(ServiceImpl.class)
public interface Service {
  void go();
}


If a client needs a Service and Guice can’t find an explicit binding, Guice will inject an instance of ServiceImpl.

By default, Guice injects a new instance every time. If you want to specify a different scope, you can annotate the implementation class, too.



@Singleton
public class ServiceImpl implements Service {
  public void go() {
    …
  }
}

Architectural Overview


We can break Guice’s architecture down into two distinct stages: startup and runtime. You build an Injector during startup and use it to inject objects at runtime.

Startup


You configure Guice by implementing Module. You pass Guice a module, Guice passes your module a Binder, and your module uses the binder to configure bindings. A binding most commonly consists of a mapping between an interface and a concrete implementation. For example:


public class MyModule implements Module {
  public void configure(Binder binder) {
    // Bind Foo to FooImpl. Guice will create a new
    // instance of FooImpl for every injection.
    binder.bind(Foo.class)
.to(FooImpl.class);

    // Bind Bar to an instance of Bar.
    Bar bar = new Bar();
    binder.bind(Bar.class).toInstance(bar);
  }
}


Guice can look at the classes you tell it about during this stage and any classes those classes know about, and tell you whether or not you’re missing any dependencies. For example, in a Struts 2 application, Guice knows about all of your actions. Guice can validate your actions and anything they transitively depend on, and fail early if necessary.

Creating an Injector entails the following steps:






  1. First, create an instance of your module and pass it to Guice.createInjector().
  2. Guice creates a Binder and passes it to your module.
  3. Your module uses the binder to define bindings.
  4. Based on the bindings you specified, Guice creates an Injector and returns it to you.
  5. You use the injector to inject an object.

Runtime


We can now use the injector we created during the first stage to inject objects and introspect on our bindings. Guice’s runtime model consists of an injector which contains some number of bindings.





A Key uniquely identifies each binding. The key consists of a type which the client depends on and an optional annotation. You can use an annotation to differentiate multiple bindings to the same type. The key’s type and annotation correspond to the type and annotation at a point of injection.

Each binding has a provider which provides instances of the necessary type. You can provide a class, and Guice will create instances of it for you. You can give Guice an instance of the type you’re binding to. You can implement your own provider, and Guice can inject dependencies into it.

Each binding also has an optional scope. Bindings have no scope by default, and Guice creates a new instance for every injection. A custom scope enables you to control whether or not Guice creates a new instance. For example, you can create one instance per HttpSession.

Bootstrapping Your Application


The idea of bootstrapping is fundamental to dependency injection. Always explicitly asking the Injector for dependencies would be using Guice as a service locator, not a dependency injection framework.

Your code should deal directly with the Injector as little as possible. Instead, you want to bootstrap your application by injecting one root object. The container can further inject dependencies into the root object’s dependencies, and so on recursively. In the end, your application should ideally have one class (if that many) which knows about the Injector, and every other class should expect to have dependencies injected.

For example, a web application framework such as Struts 2 bootstraps your application by injecting all of your actions. You might bootstrap a web service framework by injecting your service implementation classes.

Dependency injection is viral. If you’re refactoring an existing code base with a lot of static methods, you may start to feel like you’re pulling a never-ending thread. This is a Good Thing. It means dependency injection is making your code more flexible and testable.

If you get in over your head, rather than try to refactor an entire code base all in one shot, you might temporarily store a reference to the Injector in a static field somewhere or use static injection. Name the field’s class clearly though: InjectorHack and GodKillsAKittenEveryTimeYouUseMe come to mind. Keep in mind that you you’ll have to mock this class, and your unit tests will have to install an Injector here by hand, and remember to clean up afterwards.

Binding Dependencies


How does Guice know what to inject? For starters, a Key composed of a type and an optional annotation uniquely identifies a dependency. Guice refers to the mapping between a key and an implementation as a Binding. An implementation can consist of a single object, a class which Guice should also inject, or a custom provider.


When injecting a dependency, Guice first looks for an explicit binding, a binding which you specified using the Binder. The Binder API uses the builder pattern to create a domain-specific expression language. Different methods return different objects depending on the context limiting you to appropriate methods.




For example, to bind an interface Service to a concrete implementation ServiceImpl, call:



binder.bind(Service.class).to(ServiceImpl.class);


This binding matches the following the method:



@Inject
void injectService(Service service) {
  …
}



Note: In contrast to some other frameworks, Guice gives no special treatment to “setter” methods. Guice will inject any method with any number of parameters so long as the method has an @Inject annotation, even if the method is in a superclass.

DRY (Don’t Repeat Yourself)


Repeating “binder” over and over for each binding can get a little tedious. Guice provides a Module support class named AbstractModule which implicitly gives you access to Binder‘s methods. For example, we could extend AbstractModule and rewrite the above binding as:


bind(Service.class).to(ServiceImpl.class);


We’ll use this syntax throughout the rest of the guide.


Annotating Bindings


If you need multiple bindings to the same type, you can differentiate the bindings with annotations.  For example, to bind an interface Service and annotation @Blue to the concrete implementation BlueService, call:


bind(Service.class)
  .annotatedWith(Blue.class)

  .to(BlueService.class);



This binding matches the following the method:



@Inject
void injectService(@Blue Service service) {
  …
}


Notice that while @Inject goes on the method, binding annotations such as @Blue go directly on the parameter. The same goes for constructors. When using field injection, both annotations can apply directly to the field, as in this example:


@Inject @Blue Service service;

Creating Binding Annotations



Where did this @Blue annotation just mentioned come from?  You can create such an annotation easily, although the standard incantation you have to use is unfortunately a little complex:


/**
 * Indicates we want the blue version of a binding.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER})
@BindingAnnotation
public @interface Blue {}

Luckily, we don’t really have to understand it all just to use it.  But for the curious, here’s what all this boilerplate means:



  • @Retention(RUNTIME) allows your annotation to be visible at runtime.
  • @Target({FIELD, PARAMETER}) is a courtesy to your users; it prevents @Blue from being applied to methods, types, local variables, and other annotations, where it would serve no purpose.
  • @BindingAnnotation is a Guice-specific signal that you wish your annotation to be used in this way.  Guice will produce an error whenever user applies more than one binding annotation to the same injectable element.

Annotations With Attributes


If you can get by with marker annotations alone, feel free to skip to the next section.

You can also bind to annotation instances, i.e. you can have multiple bindings with the same type and annotation type, but with different annotation attribute values. If Guice can’t find a binding to an annotation instance with the necessary attribute values, it will look for a binding to the annotation type instead.

Say for example we have a binding annotation @Named with a single string attribute value.
@Retention(RUNTIME)
@Target({ FIELD, PARAMETER })
@BindingAnnotation
public @interface Named {
String value();
}

If we want to bind to @Named(“Bob”), we first need an implementation of Named. Our implementation must abide by the Annotation contract, specifically the implementations of hashCode() and equals().
class NamedAnnotation implements Named {

final String value;

public NamedAnnotation(String value) {
this.value = value;
}

public String value() {
return this.value;
}

public int hashCode() {
// This is specified in java.lang.Annotation.
return 127 * “value”.hashCode() ^ value.hashCode();
}

public boolean equals(Object o) {
if (!(o instanceof Named))
return false;
Named other = (Named) o;
return value.equals(other.value());
}

public String toString() {
return “@” + Named.class.getName() + “(value=” + value + “)”;
}

public Class<? extends Annotation> annotationType() {
return Named.class;
}
}
Now we can use this annotation implementation to create bindings to @Named.


bind(Person.class)
  .annotatedWith(new NamedAnnotation(“Bob”))
  .to(Bob.class);


This may seem like a lot of work compared to string based identifiers used by other frameworks, but keep in mind that you can’t do this at all with string-based identifiers. Also, you’ll find that you get a lot of reuse out of binding annotations.

Since identifying a binding by name is such a common use case, Guice provides a production-worthy implementation of @Named in com.google.inject.name.


Implicit Bindings


As we saw in the introduction, you don’t always have to declare bindings explicitly. In the absence of an explicit binding, Guice will try to inject and create a new instance of the class you depend on. If you depend on an interface, Guice will look for an @ImplementedBy annotation which points to the concrete implementation. Take the following explicit binding to a concrete, injectable class named Concrete for example. It basically says, bind Concrete to Concrete. That’s explicit, but also a little redundant.


bind(Concrete.class);


Removing the binding above would not affect the behavior of this class:



class Mixer {

  @Inject
  Mixer(Concrete concrete) {
    …
  }
}


So, take your pick: explicit or brief. In the event of an error, Guice will produce helpful messages either way.

Injecting Providers


Sometimes a client needs multiple instances of a dependency per injection. Other times a client may not want to actually retrieve an object until some time after the actual injection (if at all). For any binding of type T, rather than inject an instance of T directly, you can inject a Provider<T>. Then call Provider<T>.get() as necessary. For example:


@Inject
void injectAtm(Provider<Money> atm) {
  Money one = atm.get();
  Money two = atm.get();
  …
}


As you can see, the Provider interface couldn’t get much simpler so it doesn’t get in the way of easy unit testing.


Injecting Constant Values


When it comes to constant values, Guice gives special treatment to several types:



  • Primitive types (int, char, …)
  • Primitive wrapper types (Integer, Character, …)
  • Strings
  • Enums
  • Classes

First, when binding to constant values of these types, you needn’t specify the type you’re binding to. Guice can figure it out from the value. For example, given a binding annotation named TheAnswer:


bindConstant().annotatedWith(TheAnswer.class).to(42);


Has the same effect as:



bind(int.class).annotatedWith(TheAnswer.class).toInstance(42);


When it comes time to inject a value of one of these types, if Guice can’t find an explicit binding for a primitive type, it will look for a binding to the corresponding wrapper type and vice versa.

Converting Strings



If Guice still can’t find an explicit binding for one of the above types, it will look for a constant String binding with the same binding annotation and try to convert its value. For example:


bindConstant().annotatedWith(TheAnswer.class).to(“42”); // String!


Will match:



@Inject @TheAnswer int answer;


When converting, Guice will try to look up enums and classes by name. Guice converts a value once at startup which also means you get up front type checking. This feature comes in especially handy if the binding value comes from a properties file for example.

Custom Providers


Sometimes you need to create your objects manually rather than let Guice create them. For example, you might not be able to add @Inject annotations to the implementation class as it came from a 3rd party. In these cases, you can implement a custom Provider. Guice can even inject your provider class. For example:


class WidgetProvider implements Provider<Widget> {

  final Service service;

  @Inject
  WidgetProvider(Service service) {
    this.service = service;
  }

  public Widget get() {
    return new Widget(service);
  }
}


You bind Widget to WidgetProvider like so:



bind(Widget.class).toProvider(WidgetProvider.class);


Injecting the custom providers enables Guice to check the types and dependencies up front. Custom providers can reside in any scope independent of the scope of the objects they provide. By default, Guice creates a new provider instance for every injection. In the above example, if each Widget needs its own instance of Service, our code will work fine. You can specify a different scope for a custom factory using a scope annotation on the factory class or by creating a separate binding for the factory.

Example: Integrating With JNDI


Say for example we want to bind to objects from JNDI. We could implement a reusable custom provider similar to the one below. Notice we inject the JNDI Context:


package mypackage;

import com.google.inject.*;
import javax.naming.*;

class JndiProvider<T> implements Provider<T> {

  @Inject Context context;
  final String name;
  final Class<T> type;

  JndiProvider(Class<T> type, String name) {
    this.name = name;
    this.type = type;
  }

  public T get() {
    try {
      return type.cast(context.lookup(name));
    }
    catch (NamingException e) {
      throw new RuntimeException(e);
    }
  }

  /**
   * Creates a JNDI provider for the given
   * type and name.
   */
  static <T> Provider<T> fromJndi(
      Class<T> type, String name) {
    return new JndiProvider<T>(type, name);
  }
}


Thanks to generic type erasure, we must pass in the class at runtime. You could skip this step, but tracking down type casting errors later might be a little tricky (i.e. if JNDI returns an object of the wrong type).

We can use our custom JndiProvider to bind DataSource to an object from JNDI:



import com.google.inject.*;
import static mypackage.JndiProvider.fromJndi;
import javax.naming.*;
import javax.sql.DataSource;



// Bind Context to the default InitialContext.

bind(Context.class).to(InitialContext.class);

// Bind to DataSource from JNDI.
bind(DataSource.class)
    .toProvider(fromJndi(DataSource.class, “…”));

Scoping Bindings


By default, Guice creates a new object for every injection. We refer to this as having “no scope.” You can specify a scope when you configure a binding. For example, to inject the same instance every time:


bind(MySingleton.class).in(Scopes.SINGLETON);


As an alternative, you can use an annotation on your implementation class to specify the scope. Guice supports @Singleton by default:



@Singleton
class MySingleton {
  …
}


The annotation approach works with implicit bindings as well but requires that Guice create your objects. On the other hand, calling in() works with almost any binding type (binding to a single instance being an obvious exception) and overrides annotations when present. in() also accepts annotations if you don’t want a compile time dependency on your scope implementation.




Specify annotations for custom scopes using Binder.bindScope(). For example, given an annotation @SessionScoped and a Scope implementation ServletScopes.SESSION:




binder.bindScope(SessionScoped.class, ServletScopes.SESSION);

Creating Scope Annotations



Annotations used for scoping should:



  • Have a @Retention(RUNTIME) annotation so we can see the annotation at runtime.

  • Have a @Target({TYPE}) annotation. Scope annotations only apply to implementation classes..

  • Have a @ScopeAnnotation meta-annotation. Only one such annotation can apply to a given class.


For example:


/**
 * Scopes bindings to the current transaction.
 */
@Retention(RUNTIME)
@Target({TYPE})
@ScopeAnnotation
public @interface TransactionScoped {}

Eagerly Loading Bindings


Guice can wait to load singleton objects until you actually need them. This helps speed up development because your application starts faster and you only initialize what you need. However, sometimes you always want to load an object at startup. You can tell Guice to always eagerly load a singleton like so:


bind(StartupTask.class).asEagerSingleton();


We frequently use this to implement initialization logic for our application. You can control the ordering of your initialization by creating dependencies on singletons which Guice must instantiate first.

Injecting Between Scopes


You can safely inject objects from a larger scope into an object from a smaller scope, or the same scope. For example, you can inject an Http session-scoped object into an HTTP request-scoped object. However, injecting into objects with larger scopes is a different story. For example, if you injected a request-scoped object into a singleton, at best, you would get an error due to not running within an HTTP request, and at worst your singleton object would always reference an object from the first request. In these cases, you should inject a Provider<T> instead and use it to retrieve the object from the smaller scope as necessary.  Then, you should be certain to never invoke this provider when you are outside of T‘s scope (for example, when you are not servicing an HTTP request, and T is request-scoped).

Development Stages


Guice is aware that your application goes through different stages of development. You can tell it which stage the application is running in when you create a container. Guice currently supports “development” and “production.” We’ve found that tests usually fall under one stage or the other.

During development, Guice will load singleton objects on demand. This way, your application starts up fast and only loads the parts you’re testing.

In production, Guice will load all your singleton objects at startup. This helps catch errors early and takes any performance hits up front.

Your modules can also apply method interceptors and other bindings based on the current stage. For example, an interceptor might verify that you don’t use your objects out of scope during development.

Intercepting Methods


Guice supports simple method interception using the AOP Alliance API. You can bind interceptors from your modules using Binder. For example, to apply a transaction interceptor to methods annotated with @Transactional:


import static com.google.inject.matcher.Matchers.*;



binder.bindInterceptor(
  any(),                              // Match classes.
  annotatedWith(Transactional.class), // Match methods.
  new TransactionInterceptor()        // The interceptor.
);



Try to shoulder as much of the filtering as is possible on the matchers rather than in the interceptor’s body as the matching code runs only once at startup.


Static Injection


Static fields and methods make testing and reusing more difficult, but there are times where your only choice is to keep a static reference to the Injector.

For these situations, Guice supports injecting less accessible static members. For example, HTTP session objects often need to be serializable to support replication, but what if your session object depends on a container-scoped object? We can keep a transient reference to the object, but how do we look it up again upon deserialization?

We’ve found the most pragmatic solution to be static injection:


@SessionScoped
class User {

  @Inject
  static AuthorizationService authorizationService;
  …
}


Guice never performs static injection automatically.  You must use Binder to explicitly request that the Injector inject your static members after startup:




binder.requestStaticInjection(User.class);


Static injection is a necessary evil, which makes testing more difficult.  If you can find a way to avoid using it, you’ll probably be glad you did.

Optional Injection


Sometimes your code should work whether a binding exists or not. In these cases, you can use @Inject(optional=true) and Guice can override your default implementation with a bound implementation when available. For example:


@Inject(optional=true) Formatter formatter = new DefaultFormatter();


If someone creates a binding for Formatter, Guice will inject an instance from that binding. Otherwise, assuming Formatter isn’t injectable itself (see Implicit Bindings), Guice will skip the optional member.

Optional injection applies only to fields and methods, not constructors. In the case of methods, if a binding for one parameter is missing, Guice won’t inject the method at all, even if bindings to other parameters are available.

Binding to Strings


We try to avoid using strings whenever possible as they’re prone to misspellings, not tool friendly, and so on, but using strings instead of creating custom annotations can prove useful for quick and dirty code. For these situations, Guice provides @Named and Names. For example, a binding to a string name like:


import static com.google.inject.name.Names.*;



bind(named(“bob”)).to(10);


Will match injection points like:



@Inject @Named(“bob”) int score;

Struts 2 Support


To install the Guice Struts 2 plugin with Struts 2.0.6 or later, simply include guice-struts2-plugin-1.0.jar in your web application’s classpath and select Guice as your ObjectFactory implementation in your struts.xml file:


<constant name=”struts.objectFactory” value=”guice” />


Guice will inject all of your Struts 2 objects including actions and interceptors. You can even scope your actions. You can optionally specify a Module for Guice to install in your struts.xml file:



<constant name=”guice.module” value=”mypackage.MyModule”/>


If all of your bindings are implicit, you can get away without defining a module at all.

A Counting Example


Say for example that we want to count the number of requests in a session. Define a Counter object which will live on the session:


@SessionScoped
public class Counter {

  int count = 0;

  /** Increments the count and returns the new value. */
  public synchronized int increment() {
    return count++;
  }
}


Next, we can inject our counter into an action:



public class Count {

  final Counter counter;

  @Inject
  public Count(Counter counter) {
    this.counter = counter;
  }

  public String execute() {
    return SUCCESS;
  }

  public int getCount() {
    return counter.increment();
  }
}


Then create a mapping for our action in our struts.xml file:



<action name=”Count”
    class=”mypackage.Count”>
  <result>/WEB-INF/Counter.jsp</result>
</action>     


And a JSP to render the result:



<%@ taglib prefix=”s” uri=”/struts-tags” %>

<html>  
  <body>
    <h1>Counter Example</h1>
    <h3><b>Hits in this session:</b>
      <s:property value=”count”/></h3>
  </body>
</html>


We actually made this example more complicated than necessary in an attempt to illustrate more concepts. In reality, we could have done away with the separate Counter object and applied @SessionScoped to our action directly.

JMX Integration


See com.google.inject.tools.jmx.


Appendix: How the Injector resolves injection requests


The injector’s process of resolving an injection request depends on the bindings that have been made and the annotations found on the types involved.  Here is a summary of how an injection request is resolved:





  1. Observe the Java type and the optional “binding annotation” of the element to be injected. If the type is com.google.inject.Provider<T>, perform resolution for the type indicated by T instead.  Find a binding for this (type, annotation) pair. If none, skip to #4.
  2. Follow transitive bindings. If this binding links to another binding, follow this edge and check again, repeating until we reach a binding which does not link to any other binding. We are now at the most specific explicit binding for this injection request.
  3. If this binding specifies an instance or a Provider instance, we’re done; use this to fulfill the request.
  4. If, at this point, the injection request used an annotation type or value, we have failed and we produce an error.

  5. Otherwise examine the Java type for this binding; if an @ImplementedBy annotation is found, instantiate the referenced type.  If a @ProvidedBy annotation is found, instantiate the referenced provider and use it to obtain the desired object. Otherwise attempt to instantiate the type itself.

2008年最值得学习的5个Java技术


Carlos Perez发表了2008年最值得学习的5个Java技术:

1.OSGi(特别是Java动态模型方面)

OSGi service platform是一个基于Java的platform,OSGi service platform是一个开放并且提供统一接口标准的体系框架,基于这个体系框架,服务提供商,程序开发人员,软件提供商,服务网管运营商,设备提供商能够协调地联合起来开发,部署以及管理向用户提供的各种服务。

2.JCP JAVA内容仓库(Java Content Repository) 2002年一月发布

3.GWT (Google Web Toolkit ) 2006年5月发布,Google 推出的一个开发 Ajax 应用的框架,它支持用 Java 开发和调试 Ajax 应用。

4.Groovy 2004年5月发布,Groovy是一种基于JVM的敏捷开发语言,它结合了Python、Ruby和Smalltalk的许多强大的特性。Java开发者可以使用类似Java的语法来获得这些特性的支持。

5.Cloud computing 云计算(虚拟服务器设计,不使用EJB的分布式运算)


 


 


这是一个很有意思的名单,因为以上技术都算比较“老”的技术了,你认为2008最应该值得学习的java技术是什么?


 


附:什么是JCP JAVA内容仓库(Java Content Repository)?


 


JSR -170把自己定义为一个能与内容仓库互相访问的,独立的,标准的方式。同时它也对内容仓库做出了自己的定义,它认为内容仓库是一个高级的信息管理系统,该系统是是传统的数据仓库的扩展,它提供了诸如版本控制、全文检索,访问控制,内容分类、访问控制、内容事件监视等内容服务。

Java Content Repository  API(JSR-170)试图建立一套标准的API去访问内容仓库。如果你对内容管理系统(CMS)不熟悉的话,你一定会对内容仓库是什么感到疑惑。你可以这样去理解,把内容仓库理解为一个用来存储文本和二进制数据(图片,word文档,PDF等等)的数据存储应用程序。一个显著的特点是你不用关心你真正的数据到底存储在什么地方,是关系数据库?是文件系统?还是XML?不仅仅是数据的存储和读取,大多数的内容仓库还提供了更加高级的功能,例如访问控制,查找,版本控制,锁定内容等等。


 


一段时间以来市场上出现了各个厂家开发的不同的CMS系统,这些系统都建立在他们各自的内容仓库之上。
问题出现了,每个CMS开发商都提供了他们自己的API来访问内容仓库。这对应用程序的开发者带来了困扰,因为他们要学习不同的开发商提供的API,同时,他们的代码也与这些特定的API产生了绑定。

JSR-170正是为解决这一问题而出现的,它提供了一套标准的API来访问任何数据仓库。通过JSR-170,你开发代码只需要引用 javax.jcr.* 这些类和接口。它适用于任何兼容JSR-170规范的内容仓库。

我们将通过一个例子来逐步了解JSR-170。

为什么需要 Java Content Repository API

随着各个厂家各自的内容仓库实现数量的增长,人们越来越需要一组通用的编程接口来使用这些内容仓库,这就是JSR-170所要做的东西。它提供一组通用的编程接口来连接内容仓库。你可以把JSR-170理解为和JDBC类似的API,这样你可以不依赖任何具体的内容仓库实现来开发你的程序。你可以直接使用支持JSR-170的内容仓库;或者如果一些厂家的内容仓库不支持JSR-170则可以通过这些厂家提供的JSR-170驱动来完成从JSR-170与厂家特定的内容仓库的转换。

下面这张图描述了使用JSR-170开发的应用系统的结构。在该系统运行的时候,它可以操作内容仓库1,2,3中的任意一个。在这些内容仓库当中,只有2 是直接支持JSR-170的,剩下的两个都需要JSR-170驱动来和应用系统交互。注意:你的应用系统完全不用关心你的数据是如何存储的。1可能使用了关系数据库来存储,而2使用了文件系统,至于上,它甚至更前卫的使用了XML。

repositorymodel1.gif

JSR-170 API对不同的人员提供了不同的好处。

●对于开发者无需了解厂家的仓库特定的API,只要兼容JSR-170就可以通过JSR-170访问其仓库。
●对于使用CMS的公司则无需花费资金用于在不同种类CMS的内容仓库之间进行转换。
●对于CMS厂家,无需自己开发内容仓库,而专注于开发CMS应用。


 


来自:http://www.iocblog.net/static/2007/475.html

Googlipse-不错的GWT Eclipse插件


最近发现一个很不错的用于在Eclipse IDE下应用GWT开发AJAX的插件,叫Googlipse,名字还很好记,呵呵.
它的最近发布版本是0.5.4版,可以支持GWT1.4.60,不过在sourceforge.net里的邮件列表里发现原来这个插件已经停止开发与BUG修复了,真是可惜.现在把安装与使用方法简单翻译一下,以防自己以后忘记,也方便大家学习.不过,本人E文也一般,大致上给翻译一下, 翻译的很生硬,不过主要的信息还是体现出来了,大家将就一下


准备:


1) 下载:http://sourceforge.net/projects/googlipse


2) 安装前提:
 a) Eclipse 3.2 with WebTools Platform 1.5(一定要装,)
 b) 已经安装了JDK 1.5以上
 c) 还需要下载 Google Web Toolkit , 网址是: http://code.google.com/webtoolkit/


 


安装插件到制作实例的全过程(英文是从官方网站上COPY的)


 (*) Drop the com.googlipse.gwt_<version>.jar file in your eclipse\plugins folder
 将com.googlipse.gwt_<version>.jar文件放到你的Eclipse安装文件夹中的plugins文件夹下 (译者注: 我这里用的的com.googlipse.gwt_0.5.4.jar)


 (*) Open Eclipse. Select Window->Preferences->Googlipse and set GWT home to the directory where you have installed the Google Web Toolkit.
 打开Eclipse, 选择Window->Preferences->Googlipse , 设置GWT安装目录


 (*) You are all set to code.
 (此句不知该怎么翻译..-_-!)


Adding Googlipse to your project:
 Googlipse is implemented as a WTP Facet. When creating a new Dynamic Web Project, select Googlipse in the Project Facets page. If you already have a Dynamic Web Project, you can add Googlipse facet by selecting Project->Properties->Project Facets(Please make sure you don’t have gwt-user.jar in your classpath). In case you didn’t like Googlipse, you can remove the facet.


添加Googlipse到你的工程:
 Googlipse是一个实现了WTP的插件(Facet这个单词不知道具体要怎么翻译,暂且翻译成”插件”). 当新建一个的动态WEB工程时,可在工程模块页面中选择Googlipse.如果已经有一个动态WEB工程时,可以通过 Project->Properties->Project Facets 添加Googlipse插件(请确认gwt-user.jar在不在你的classpath中). 假使你不喜欢Googlipse,你也可以移除它.


Creating a Module:
 Once you have a Dynamic Web Project with Googlipse facet, you can add a new module by File->New->Other->Googlipse->Gwt Module. Modules can be created only in valid java packages (default package is not allowed). Either you can type in the package (with project & source folder) in the location field or you can select it by clicking Browse button. You can also click the Create button to create a new package. Next type in the name of the module. Click Finish, you will have all the artifacts for the module generated.


新建一个模块:
 当有了一个包含Googlipse插件的动态WEB工程后,你可以通过 File->New->Other->Googlipse->Gwt Module 添加一个新的模块. 这些模块只能被创建到一个有效的包中(默认包名不允许使用),
你可以指定包名(包含工程名和源文件夹名)或通过点击Browse按钮选择包. 你也可以自己新建一个包. 然后输入模块名称,点击Finish, 就可以得到这个模块生成的组件.
 
Adding a Remote Service;


 Note :A Remote Service will be created only in a module. So if you don’t have a module, you need to create one using the New Module wizard, before this step.
 You can select File->New->Other->Googlipse->Gwt Remote Service. Click the Browse button and select the module (the gwt.xml file). Type the name and uri for the service and click Finish. Now the artifacts for the remote service will be generated. (You have to add an entry in the gwt.xml file manually. Googlipse doesn’t add it. This feature will be implemented in future versions)


添加远程服务:
 提示: 一个模块中只能创建一个远程服务. 在这一步之前, 如果你没有模块, 你需要使用New Module向导创建一个新模块
 选择: File->New->Other->Googlipse->Gwt Remote Service , 点击Browse按钮,选择当前模块(即gwt.xml文件),输入该服务的名程和uri地址,然后点击Finish. 现在这个远程服务的组件就已经生成了.(你必须手动地在gwt.xml文件中添加配置. Googlipse并不自动添加, 在以后的版本中将支持该功能)
 
Adding a Remote Service method:


 You can open the RemoteService interface and add/change methods in it. You need to provide the implementation of those methods in RemoteServiceImpl class, but thanks to Googlipse, you don’t have to do anything in RemoteServiceAsync. Googlipse will automatically update the corresponding Async file whenever a RemoteService interface is changed.


添加一个远程服务的方法:
 你可以打开RemoteService接口并添加/修改其中的方法. 你需要在RemoteServiceImpl类中提供这些方法的实现, 不过有了Googlipse, 你不需要做任何事情,当RemoteService接口改变时Googlipse会自动更新相应的文件
 
Calling a method using Remote Service:
 The utility class in the Remote service should help you in making the remote call.
 
 MyRemoteServiceAsync async = MyRemoteService.Util.getInstance();
 async.makeRemoteCall(param1, param2, callback);
 
在远程服务中调用一个方法:
 在远程服务的实体类会帮你产生相应的远程调用.
 MyRemoteServiceAsync async = MyRemoteService.Util.getInstance();
 async.makeRemoteCall(param1, param2, callback);


Running/Debugging a Gwt Application:
 Select Run->Run/Debug to activate the Lauch configuration dialog box. Double Click “Gwt Application”. In the main page, you can select the Project & Module you want to run. In the parameters page you can select the parameters such as port and log level. Click Run to execute the GwtShell & bring up your application. The laucher will add the jar files & all the source folders in the project to your application.


运行/调试:
 选择 Run->Run/Debug 显示Lauch configuration对话框, 双击”Gwt Application”. 在main页面中,选择要运行的工程和模块.在parameters页面中选择参数,如端口和日志级别. 点击Run,即可执行GwtShell并加载你的应用程序, GwtShell将添加工程中的jar包和所有的源文件夹到你的应用程序中

click Web Framework 1.4发布

click Web Framework 1.4发布,Click是一个高性能的J2EE Web应用程序框架适用商业Java开发者,它是基于页面和组件的java web框架,基于事件编程模型,使用Velocity模板作为页面视图,没有复杂的抽象和定义,简单易学,商业开发者能够在一天内把它运行起来。

1.4版本的新功能包括:

1。Stateful page支持,使得开发复杂页面和页面流程更加简单




Java代码


  1. package com.mycorp.page;   

  2.   

  3. import java.io.Serializable;   

  4.   

  5. import net.sf.click.Page;   

  6.     

  7. public class SearchPage extends Page implements Serializable {   

  8.   

  9.     public SearchPage() {   

  10.         setStateful(true);   

  11.         ..   

  12.     }   

  13. }   



2。新的Control event函数 – onInit(), onRender() and onDestroy().

3。执行性能增强

4。新的PerformanceFilter使你的应用程序付出微小代价就能采用Yahoo style performance


 


5。新增对Cayenne ORM versions 2.x and 3.x的支持


 


。。。


 


如果对click Web Framework 感兴趣 请访问:


精確的字符串截取方法 java

发开项目需要,在网上找了很久都没有打到.于是自己动手写了一下.贡献出来给有需要的人.如果有什么问题可以加我MSN:[email protected] 讨论讨论


源代码:


 /**
  * 截取字符串的前targetCount个字符
  * @param str 被处理字符串
  * @param targetCount 截取长度
  * @version 1.1
  * @author Strong Yuan
  * @return String
  */
 public static String subContentStringOrialBytes(String str,int targetCount){
  return subContentStringOrialBytes(str,targetCount,”…”);
 }
 /**
  * 获取指定长度字符串的字节长
  * @param str 被处理字符串
  * @param maxlength 截取长度
  * @author Strong Yuan
  * @version 1.1
  * @return String
  */
 private static long getStringByteLength(String str,int maxlength){
  if(str==null)
   return 0;
  int tmp_len = maxlength;
  
  if(str.length()<maxlength)
   tmp_len = str.length();
  else if(str.length()>maxlength*2)
   tmp_len = maxlength*2;
  
  char[] tempchar = str.substring(0, tmp_len).toCharArray();


  int intVariable = 0;
  String s1 = null;
  for(int i=0;i<tempchar.length && intVariable<=maxlength;i++){
   s1 = String.valueOf(tempchar[i]);
   intVariable += s1.getBytes().length;
  }
  s1= null;
  tempchar = null;
  return intVariable;
 }
 /**
  * 截取指定长度的字符串,基于bytes,即是中文的长度为2,英文为1
  * @param str 被处理字符串
  * @param targetCount 截取长度
  * @param more 后缀字符串
  * @author Strong Yuan
  * @version 1.1
  * @return
  */
 public static String subContentStringOrialBytes(String str, int targetCount,String more)
 {
  if (str == null)
   return “”;
  int initVariable = 0;
  StringBuffer restr = new StringBuffer();
  if (getStringByteLength(str,targetCount) <= targetCount)
   return str;


  String s1=null;
  byte[] b;
  char[] tempchar = str.toCharArray();
  for (int i = 0; (i < tempchar.length && targetCount > initVariable); i++) {
   s1 = String.valueOf(tempchar[i]);
   b = s1.getBytes();
   initVariable += b.length;
   restr.append(tempchar[i]);
  }


  if (targetCount == initVariable || (targetCount == initVariable – 1)) {
   restr.append(more);
  }
  return restr.toString();
 }
 /**
  * 截取指定长度的字符串,存在问题,但效率会高一点点.just a little
  * @param str 被处理字符串
  * @param targetCount 截取长度
  * @param more 后缀字符串
  * @version 1.1
  * @author Strong Yuan
  * @return String
  */
 public static String subContentStringOrial(String str,int targetCount){
  return subContentStringOrial(str,targetCount,”…”);
 } 
 /**
  * 截取指定长度的字符串,存在问题,但效率会高一点点.just a little
  * @param str 被处理字符串
  * @param targetCount 截取长度
  * @param more 后缀字符串
  * @author Strong Yuan
  * @return String
  */
 public static String subContentStringOrial(String str, int targetCount,String more)
 {
  if (str == null)
   return “”;
  int initVariable = 0;
  StringBuffer restr = new StringBuffer();
  if (str.length() <= targetCount)
   return str;


  String s1=null;
  byte[] b;
  char[] tempchar = str.toCharArray();
  for (int i = 0; (i < tempchar.length && targetCount > initVariable); i++) {
   s1 = String.valueOf(tempchar[i]);
   b = s1.getBytes();
   initVariable += b.length;
   restr.append(tempchar[i]);
  }


  if (targetCount == initVariable || (targetCount == initVariable – 1)) {
   restr.append(more);
  }
  return restr.toString();
 }


下面是性能测试:

 

public static void main(String[] args){

  int maxLength = 28;  
  String str =”当奥运圣火格式化字符串长度,超出部分显示省略号,区分汉字跟字母。汉字2个字节,字母数字一个字节格式化字符串长度,超出部分显示省略号,区分汉字跟字母。汉字2个字节,字母数字一个字节格式化字符串长度,超出部分显示省略号,区分汉字跟字母。汉字2个字节,字母数字一个字节格式化字符串长度,超出部分显示省略号,区分汉字跟字母。汉字2个字节,字母数字一个字节格式化字符串长度,超出部分显示省略号,区分汉字跟字母。汉字2个字节,字母数字一个字节格式化字符串长度,超出部分显示省略号,区分汉字跟字母。汉字2个字节,字母数字一个字节格式化字符串长度,超出部分显示省略号,区分汉字跟字母。汉字2个字节,字母数字一个字节格式化字符串长度,超出部分显示省略号,区分汉字跟字母。汉字2个字节,字母数字一个字节格式化字符串长度,超出部分显示省略号,区分汉字跟字母。汉字2个字节,字母数字一个字节格式化字符串长度,超出部分显示省略号,区分汉字跟字母。汉字2个字节,字母数字一个字节格式化字符串长度,超出部分显示省略号,区分汉字跟字母。汉字2个字节,字母数字一个字节格式化字符串长度,超出部分显示省略号,区分汉字跟字母。汉字2个字节,字母数字一个字节格式化字符串长度,超出部分显示省略号,区分汉字跟字母。汉字2个字节,字母数字一个字节格式化字符串长度,超出部分显示省略号,区分汉字跟字母。汉字2个字节,字母数字一个字节格式化字符串长度,超出部分显示省略号,区分汉字跟字母。汉字2个字节,字母数字一个字节格式化字符串长度,超出部分显示省略号,区分汉字跟字母。汉字2个字节,字母数字一个字节格式化字符串长度,超出部分显示省略号,区分汉字跟字母。汉字2个字节,字母数字一个字节格式化字符串长度,超出部分显示省略号,区分汉字跟字母。汉字2个字节,字母数字一个字节格式化字符串长度,超出部分显示省略号,区分汉字跟字母。汉字2个字节,字母数字一个字节格式化字符串长度,超出部分显示省略号,区分汉字跟字母。汉字2个字节,字母数字一个字节格式化字符串长度,超出部分显示省略号,区分汉字跟字母。汉字2个字节,字母数字一个字节格式化字符串长度,超出部分显示省略号,区分汉字跟字母。汉字2个字节,字母数字一个字节”;

  long curr = System.currentTimeMillis();
  String aa = null;
  for(int i =0;i<=100000;i++){
   aa = htmlFilter.subContentStringOrial(str, maxLength);
  }
  System.out.println(“结果: “+aa);
  System.out.println(“耗时: ” + (System.currentTimeMillis()-curr)+” ms”);
 
  curr = System.currentTimeMillis();
  for(int i =0;i<=100000;i++){
   aa = htmlFilter.subContentStringOrialBytes(str, maxLength);
  }
  System.out.println(“结果: “+aa);  
  System.out.println(“耗时: ” + (System.currentTimeMillis()-curr)+” ms”);
  

  System.out.println(htmlFilter.subContentStringOrial(“[原创]山西临汾矿难3主犯被判无期dfasdfasdfasdf万人听判”, maxLength));
  System.out.println(htmlFilter.subContentStringOrialBytes(“[原创]山西临汾矿难3主犯被判无期dfasdfasdfasdf万人听判”, maxLength,”…”));
  //存在问题,当str.length()小于maxLength时,就不进行截取
  System.out.println(htmlFilter.subContentStringOrial(“[原创]山西临汾矿难3主犯被判无期万人听判”, maxLength));
  System.out.println(htmlFilter.subContentStringOrialBytes(“[原创]山西临汾矿难3主犯被判无期万人听判”, maxLength,”…”));

}

 

最后输出结果:

 

结果: 当奥运圣火格式化字符
耗时: 1183 ms
结果: 当奥运圣火格式化字符
耗时: 1834 ms
[原创]dfasdfasdfasdf
[原创]dfasdfasdfasdf
[原创]山西临汾矿难3主
[原创]山西临汾矿难3主
[原创]山西临汾矿难3主犯被判无期万人听判判无期万人听判
[原创]山西临汾矿难3主


resin 3.1使用总结.

  使用resin已经有四、五年了,但以前都是做一些小系统,resin的压力并不大,近段时间做一个大系统,日平均ip上10万,resin的压力非常的大,除了对程序做优化以外,resin 的优化也小不了。

 

 

一、优化配置

  修改 conf/resin.conf 文章中的 JVM参数

 

<jvm-arg>-Xms512m</jvm-arg>
<jvm-arg>-Xss128k</jvm-arg>
<jvm-arg>-Xmn184m</jvm-arg>
<jvm-arg>-XX:ParallelGCThreads=20</jvm-arg>
<jvm-arg>-XX:+UseConcMarkSweepGC</jvm-arg>
<jvm-arg>-XX:+UseParNewGC</jvm-arg>
<jvm-arg>-Xdebug</jvm-arg>
<jvm-arg>-Xloggc:gc.log</jvm-arg>

 

  修改 最大thread-max为2500

      <!– Maximum number of threads. –>
      <thread-max>2500</thread-max>

      <!– Configures the socket timeout –>
      <socket-timeout>65s</socket-timeout>
        
      <!– Configures the keepalive –>
      <keepalive-max>10240</keepalive-max>
      <keepalive-timeout>30s</keepalive-timeout>

 

二、利用resin-admin监控resin运行情况。


 

第一行是Thread pool情况,如果发现Peak大于thread max,就应该修改conf/resin.conf 中的thread-max,相应的增大thread-max。

第二行是Threads,如果长期出现在这里而又不是SUN的方法,或者resin的方法的话,就要对这些方法进行测试、优化。

JVM调优总结 -Xms -Xmx -Xmn -Xss

三、常见配置举例


  1. 堆大小设置
    JVM 中最大堆大小有三方面限制:相关操作系统的数据模型(32-bt还是64-bit)限制;系统的可用虚拟内存限制;系统的可用物理内存限制。32位系统下,一般限制在1.5G~2G;64为操作系统对内存无限制。我在Windows Server 2003 系统,3.5G物理内存,JDK5.0下测试,最大可设置为1478m。
    典型设置:

    • java -Xmx3550m -Xms3550m -Xmn2g -Xss128k
      Xmx3550m:设置JVM最大可用内存为3550M。
      -Xms3550m
      :设置JVM促使内存为3550m。此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存。
      -Xmn2g
      :设置年轻代大小为2G。整个堆大小=年轻代大小 + 年老代大小 + 持久代大小。持久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。
      -Xss128k
      :设置每个线程的堆栈大小。JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。更具应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。

    • java -Xmx3550m -Xms3550m -Xss128k -XX:NewRatio=4 -XX:SurvivorRatio=4 -XX:MaxPermSize=16m -XX:MaxTenuringThreshold=0
      -XX:NewRatio=4
      :设置年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代)。设置为4,则年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5
      -XX:SurvivorRatio=4
      :设置年轻代中Eden区与Survivor区的大小比值。设置为4,则两个Survivor区与一个Eden区的比值为2:4,一个Survivor区占整个年轻代的1/6
      -XX:MaxPermSize=16m:设置持久代大小为16m。
      -XX:MaxTenuringThreshold=0:设置垃圾最大年龄。如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代。对于年老代比较多的应用,可以提高效率。如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活时间,增加在年轻代即被回收的概论。

  2. 回收器选择
    JVM给了三种选择:串行收集器、并行收集器、并发收集器,但是串行收集器只适用于小数据量的情况,所以这里的选择主要针对并行收集器和并发收集器。默认情况下,JDK5.0以前都是使用串行收集器,如果想使用其他收集器需要在启动时加入相应参数。JDK5.0以后,JVM会根据当前系统配置进行判断。

    1. 吞吐量优先的并行收集器
      如上文所述,并行收集器主要以到达一定的吞吐量为目标,适用于科学技术和后台处理等。
      典型配置

      • java -Xmx3800m -Xms3800m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20
        -XX:+UseParallelGC
        :选择垃圾收集器为并行收集器。此配置仅对年轻代有效。即上述配置下,年轻代使用并发收集,而年老代仍旧使用串行收集。
        -XX:ParallelGCThreads=20:配置并行收集器的线程数,即:同时多少个线程一起进行垃圾回收。此值最好配置与处理器数目相等。

      • java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20 -XX:+UseParallelOldGC
        -XX:+UseParallelOldGC:配置年老代垃圾收集方式为并行收集。JDK6.0支持对年老代并行收集。

      • java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC  -XX:MaxGCPauseMillis=100
        -XX:MaxGCPauseMillis=100:设置每次年轻代垃圾回收的最长时间,如果无法满足此时间,JVM会自动调整年轻代大小,以满足此值。

      • java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC  -XX:MaxGCPauseMillis=100 -XX:+UseAdaptiveSizePolicy
        -XX:+UseAdaptiveSizePolicy
        :设置此选项后,并行收集器会自动选择年轻代区大小和相应的Survivor区比例,以达到目标系统规定的最低相应时间或者收集频率等,此值建议使用并行收集器时,一直打开。

    2. 响应时间优先的并发收集器
      如上文所述,并发收集器主要是保证系统的响应时间,减少垃圾收集时的停顿时间。适用于应用服务器、电信领域等。
      典型配置

      • java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:ParallelGCThreads=20 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC
        -XX:+UseConcMarkSweepGC:设置年老代为并发收集。测试中配置这个以后,-XX:NewRatio=4的配置失效了,原因不明。所以,此时年轻代大小最好用-Xmn设置。
        -XX:+UseParNewGC:设置年轻代为并行收集。可与CMS收集同时使用。JDK5.0以上,JVM会根据系统配置自行设置,所以无需再设置此值。

      • java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseConcMarkSweepGC -XX:CMSFullGCsBeforeCompaction=5 -XX:+UseCMSCompactAtFullCollection
        -XX:CMSFullGCsBeforeCompaction:由于并发收集器不对内存空间进行压缩、整理,所以运行一段时间以后会产生“碎片”,使得运行效率降低。此值设置运行多少次GC以后对内存空间进行压缩、整理。
        -XX:+UseCMSCompactAtFullCollection:打开对年老代的压缩。可能会影响性能,但是可以消除碎片

  3. 辅助信息
    JVM提供了大量命令行参数,打印信息,供调试使用。主要有以下一些:

    • -XX:+PrintGC
      输出形式:[GC 118250K->113543K(130112K), 0.0094143 secs]

                      [Full GC 121376K->10414K(130112K), 0.0650971 secs]


    • -XX:+PrintGCDetails
      输出形式:[GC [DefNew: 8614K->781K(9088K), 0.0123035 secs] 118250K->113543K(130112K), 0.0124633 secs]

                      [GC [DefNew: 8614K->8614K(9088K), 0.0000665 secs][Tenured: 112761K->10414K(121024K), 0.0433488 secs] 121376K->10414K(130112K), 0.0436268 secs]


    • -XX:+PrintGCTimeStamps -XX:+PrintGC:PrintGCTimeStamps可与上面两个混合使用
      输出形式:11.851: [GC 98328K->93620K(130112K), 0.0082960 secs]

    • -XX:+PrintGCApplicationConcurrentTime:打印每次垃圾回收前,程序未中断的执行时间。可与上面混合使用
      输出形式:Application time: 0.5291524 seconds

    • -XX:+PrintGCApplicationStoppedTime:打印垃圾回收期间程序暂停的时间。可与上面混合使用
      输出形式:Total time for which application threads were stopped: 0.0468229 seconds

    • -XX:PrintHeapAtGC:打印GC前后的详细堆栈信息
      输出形式:
      34.702: [GC {Heap before gc invocations=7:
       def new generation   total 55296K, used 52568K [0x1ebd0000, 0x227d0000, 0x227d0000)
      eden space 49152K,  99% used [0x1ebd0000, 0x21bce430, 0x21bd0000)
      from space 6144K,  55% used [0x221d0000, 0x22527e10, 0x227d0000)
        to   space 6144K,   0% used [0x21bd0000, 0x21bd0000, 0x221d0000)
       tenured generation   total 69632K, used 2696K [0x227d0000, 0x26bd0000, 0x26bd0000)
      the space 69632K,   3% used [0x227d0000, 0x22a720f8, 0x22a72200, 0x26bd0000)
       compacting perm gen  total 8192K, used 2898K [0x26bd0000, 0x273d0000, 0x2abd0000)
         the space 8192K,  35% used [0x26bd0000, 0x26ea4ba8, 0x26ea4c00, 0x273d0000)
          ro space 8192K,  66% used [0x2abd0000, 0x2b12bcc0, 0x2b12be00, 0x2b3d0000)
          rw space 12288K,  46% used [0x2b3d0000, 0x2b972060, 0x2b972200, 0x2bfd0000)
      34.735: [DefNew: 52568K->3433K(55296K), 0.0072126 secs] 55264K->6615K(124928K)Heap after gc invocations=8:
       def new generation   total 55296K, used 3433K [0x1ebd0000, 0x227d0000, 0x227d0000)
      eden space 49152K,   0% used [0x1ebd0000, 0x1ebd0000, 0x21bd0000)
        from space 6144K,  55% used [0x21bd0000, 0x21f2a5e8, 0x221d0000)
        to   space 6144K,   0% used [0x221d0000, 0x221d0000, 0x227d0000)
       tenured generation   total 69632K, used 3182K [0x227d0000, 0x26bd0000, 0x26bd0000)
      the space 69632K,   4% used [0x227d0000, 0x22aeb958, 0x22aeba00, 0x26bd0000)
       compacting perm gen  total 8192K, used 2898K [0x26bd0000, 0x273d0000, 0x2abd0000)
         the space 8192K,  35% used [0x26bd0000, 0x26ea4ba8, 0x26ea4c00, 0x273d0000)
          ro space 8192K,  66% used [0x2abd0000, 0x2b12bcc0, 0x2b12be00, 0x2b3d0000)
          rw space 12288K,  46% used [0x2b3d0000, 0x2b972060, 0x2b972200, 0x2bfd0000)
      }
      , 0.0757599 secs]

    • -Xloggc:filename:与上面几个配合使用,把相关日志信息记录到文件以便分析。

  4. 常见配置汇总

    1. 堆设置

      • -Xms:初始堆大小
      • -Xmx:最大堆大小
      • -XX:NewSize=n:设置年轻代大小
      • -XX:NewRatio=n:设置年轻代和年老代的比值。如:为3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4
      • -XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5
      • -XX:MaxPermSize=n:设置持久代大小

    2. 收集器设置

      • -XX:+UseSerialGC:设置串行收集器
      • -XX:+UseParallelGC:设置并行收集器
      • -XX:+UseParalledlOldGC:设置并行年老代收集器
      • -XX:+UseConcMarkSweepGC:设置并发收集器

    3. 垃圾回收统计信息

      • -XX:+PrintGC
      • -XX:+PrintGCDetails
      • -XX:+PrintGCTimeStamps
      • -Xloggc:filename

    4. 并行收集器设置

      • -XX:ParallelGCThreads=n:设置并行收集器收集时使用的CPU数。并行收集线程数。
      • -XX:MaxGCPauseMillis=n:设置并行收集最大暂停时间
      • -XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比。公式为1/(1+n)

    5. 并发收集器设置

      • -XX:+CMSIncrementalMode:设置为增量模式。适用于单CPU情况。
      • -XX:ParallelGCThreads=n:设置并发收集器年轻代收集方式为并行收集时,使用的CPU数。并行收集线程数。

四、调优总结

  1. 年轻代大小选择

    • 响应时间优先的应用尽可能设大,直到接近系统的最低响应时间限制(根据实际情况选择)。在此种情况下,年轻代收集发生的频率也是最小的。同时,减少到达年老代的对象。
    • 吞吐量优先的应用:尽可能的设置大,可能到达Gbit的程度。因为对响应时间没有要求,垃圾收集可以并行进行,一般适合8CPU以上的应用。

  2. 年老代大小选择

    • 响应时间优先的应用:年老代使用并发收集器,所以其大小需要小心设置,一般要考虑并发会话率会话持续时间等一些参数。如果堆设置小了,可以会造成内存碎片、高回收频率以及应用暂停而使用传统的标记清除方式;如果堆大了,则需要较长的收集时间。最优化的方案,一般需要参考以下数据获得:

      • 并发垃圾收集信息
      • 持久代并发收集次数
      • 传统GC信息
      • 花在年轻代和年老代回收上的时间比例
      减少年轻代和年老代花费的时间,一般会提高应用的效率

    • 吞吐量优先的应用:一般吞吐量优先的应用都有一个很大的年轻代和一个较小的年老代。原因是,这样可以尽可能回收掉大部分短期对象,减少中期的对象,而年老代尽存放长期存活对象。

  3. 较小堆引起的碎片问题
    因为年老代的并发收集器使用标记、清除算法,所以不会对堆进行压缩。当收集器回收时,他会把相邻的空间进行合并,这样可以分配给较大的对象。但是,当堆空间较小时,运行一段时间以后,就会出现“碎片”,如果并发收集器找不到足够的空间,那么并发收集器将会停止,然后使用传统的标记、清除方式进行回收。如果出现“碎片”,可能需要进行如下配置:

    • -XX:+UseCMSCompactAtFullCollection:使用并发收集器时,开启对年老代的压缩。
    • -XX:CMSFullGCsBeforeCompaction=0:上面配置开启的情况下,这里设置多少次Full GC后,对年老代进行压缩

五、参考文献

JVM详解之Java垃圾回收机制详解和调优

1.JVM的gc概述

  gc即垃圾收集机制是指jvm用于释放那些不再使用的对象所占用的内存。java语言并不要求jvm有gc,也没有规定gc如何工作。不过常用的jvm都有gc,而且大多数gc都使用类似的算法管理内存和执行收集操作。

  在充分理解了垃圾收集算法和执行过程后,才能有效的优化它的性能。有些垃圾收集专用于特殊的应用程序。比如,实时应用程序主要是为了避免垃圾收集中断,而大多数OLTP应用程序则注重整体效率。理解了应用程序的工作负荷和jvm支持的垃圾收集算法,便可以进行优化配置垃圾收集器。

  垃圾收集的目的在于清除不再使用的对象。gc通过确定对象是否被活动对象引用来确定是否收集该对象。gc首先要判断该对象是否是时候可以收集。两种常用的方法是引用计数和对象引用遍历。

  1.1.引用计数

  引用计数存储对特定对象的所有引用数,也就是说,当应用程序创建引用以及引用超出范围时,jvm必须适当增减引用数。当某对象的引用数为0时,便可以进行垃圾收集。

  1.2.对象引用遍历

  早期的jvm使用引用计数,现在大多数jvm采用对象引用遍历。对象引用遍历从一组对象开始,沿着整个对象图上的每条链接,递归确定可到达(reachable)的对象。如果某对象不能从这些根对象的一个(至少一个)到达,则将它作为垃圾收集。在对象遍历阶段,gc必须记住哪些对象可以到达,以便删除不可到达的对象,这称为标记(marking)对象。

  下一步,gc要删除不可到达的对象。删除时,有些gc只是简单的扫描堆栈,删除未标记的未标记的对象,并释放它们的内存以生成新的对象,这叫做清除(sweeping)。这种方法的问题在于内存会分成好多小段,而它们不足以用于新的对象,但是组合起来却很大。因此,许多gc可以重新组织内存中的对象,并进行压缩(compact),形成可利用的空间。

  为此,gc需要停止其他的活动活动。这种方法意味着所有与应用程序相关的工作停止,只有gc运行。结果,在响应期间增减了许多混杂请求。另外,更复杂的 gc不断增加或同时运行以减少或者清除应用程序的中断。有的gc使用单线程完成这项工作,有的则采用多线程以增加效率。

2.几种垃圾回收机制

  2.1.标记-清除收集器

  这种收集器首先遍历对象图并标记可到达的对象,然后扫描堆栈以寻找未标记对象并释放它们的内存。这种收集器一般使用单线程工作并停止其他操作。

  2.2.标记-压缩收集器

  有时也叫标记-清除-压缩收集器,与标记-清除收集器有相同的标记阶段。在第二阶段,则把标记对象复制到堆栈的新域中以便压缩堆栈。这种收集器也停止其他操作。

  2.3.复制收集器

  这种收集器将堆栈分为两个域,常称为半空间。每次仅使用一半的空间,jvm生成的新对象则放在另一半空间中。gc运行时,它把可到达对象复制到另一半空间,从而压缩了堆栈。这种方法适用于短生存期的对象,持续复制长生存期的对象则导致效率降低。

  2.4.增量收集器

  增量收集器把堆栈分为多个域,每次仅从一个域收集垃圾。这会造成较小的应用程序中断。

  2.5.分代收集器

  这种收集器把堆栈分为两个或多个域,用以存放不同寿命的对象。jvm生成的新对象一般放在其中的某个域中。过一段时间,继续存在的对象将获得使用期并转入更长寿命的域中。分代收集器对不同的域使用不同的算法以优化性能。

  2.6.并发收集器

  并发收集器与应用程序同时运行。这些收集器在某点上(比如压缩时)一般都不得不停止其他操作以完成特定的任务,但是因为其他应用程序可进行其他的后台操作,所以中断其他处理的实际时间大大降低。

  2.7.并行收集器

  并行收集器使用某种传统的算法并使用多线程并行的执行它们的工作。在多cpu机器上使用多线程技术可以显著的提高java应用程序的可扩展性。



3.Sun HotSpot

  1.4.1 JVM堆大小的调整

  Sun HotSpot 1.4.1使用分代收集器,它把堆分为三个主要的域:新域、旧域以及永久域。Jvm生成的所有新对象放在新域中。一旦对象经历了一定数量的垃圾收集循环后,便获得使用期并进入旧域。在永久域中jvm则存储class和method对象。就配置而言,永久域是一个独立域并且不认为是堆的一部分。

  下面介绍如何控制这些域的大小。可使用-Xms和-Xmx 控制整个堆的原始大小或最大值。

  下面的命令是把初始大小设置为128M:

  java –Xms128m

  –Xmx256m为控制新域的大小,可使用-XX:NewRatio设置新域在堆中所占的比例。

  下面的命令把整个堆设置成128m,新域比率设置成3,即新域与旧域比例为1:3,新域为堆的1/4或32M:

java –Xms128m –Xmx128m
–XX:NewRatio =3可使用-XX:NewSize和-XX:MaxNewsize设置新域的初始值和最大值。

  下面的命令把新域的初始值和最大值设置成64m:

java –Xms256m –Xmx256m –Xmn64m

  永久域默认大小为4m。运行程序时,jvm会调整永久域的大小以满足需要。每次调整时,jvm会对堆进行一次完全的垃圾收集。

  使用-XX:MaxPerSize标志来增加永久域搭大小。在WebLogic Server应用程序加载较多类时,经常需要增加永久域的最大值。当jvm加载类时,永久域中的对象急剧增加,从而使jvm不断调整永久域大小。为了避免调整,可使用-XX:PerSize标志设置初始值。

  下面把永久域初始值设置成32m,最大值设置成64m。

java -Xms512m -Xmx512m -Xmn128m -XX:PermSize=32m -XX:MaxPermSize=64m

  默认状态下,HotSpot在新域中使用复制收集器。该域一般分为三个部分。第一部分为Eden,用于生成新的对象。另两部分称为救助空间,当Eden 充满时,收集器停止应用程序,把所有可到达对象复制到当前的from救助空间,一旦当前的from救助空间充满,收集器则把可到达对象复制到当前的to救助空间。From和to救助空间互换角色。维持活动的对象将在救助空间不断复制,直到它们获得使用期并转入旧域。使用-XX:SurvivorRatio 可控制新域子空间的大小。

  同NewRation一样,SurvivorRation规定某救助域与Eden空间的比值。比如,以下命令把新域设置成64m,Eden占32m,每个救助域各占16m:

java -Xms256m -Xmx256m -Xmn64m -XX:SurvivorRation =2

  如前所述,默认状态下HotSpot对新域使用复制收集器,对旧域使用标记-清除-压缩收集器。在新域中使用复制收集器有很多意义,因为应用程序生成的大部分对象是短寿命的。理想状态下,所有过渡对象在移出Eden空间时将被收集。如果能够这样的话,并且移出Eden空间的对象是长寿命的,那么理论上可以立即把它们移进旧域,避免在救助空间反复复制。但是,应用程序不能适合这种理想状态,因为它们有一小部分中长寿命的对象。最好是保持这些中长寿命的对象并放在新域中,因为复制小部分的对象总比压缩旧域廉价。为控制新域中对象的复制,可用-XX:TargetSurvivorRatio控制救助空间的比例(该值是设置救助空间的使用比例。如救助空间位1M,该值50表示可用500K)。该值是一个百分比,默认值是50。当较大的堆栈使用较低的 sruvivorratio时,应增加该值到80至90,以更好利用救助空间。用-XX:maxtenuring threshold可控制上限。

  为放置所有的复制全部发生以及希望对象从eden扩展到旧域,可以把MaxTenuring Threshold设置成0。设置完成后,实际上就不再使用救助空间了,因此应把SurvivorRatio设成最大值以最大化Eden空间,设置如下:

java … -XX:MaxTenuringThreshold=0 –XX:SurvivorRatio=50000 …

4.BEA JRockit JVM的使用

  Bea WebLogic 8.1使用的新的JVM用于Intel平台。在Bea安装完毕的目录下可以看到有一个类似于jrockit81sp1_141_03的文件夹。这就是 Bea新JVM所在目录。不同于HotSpot把Java字节码编译成本地码,它预先编译成类。JRockit还提供了更细致的功能用以观察JVM的运行状态,主要是独立的GUI控制台(只能适用于使用Jrockit才能使用jrockit81sp1_141_03自带的console监控一些cpu及 memory参数)或者WebLogic Server控制台。

  Bea JRockit JVM支持4种垃圾收集器:

  4.1.1.分代复制收集器

  它与默认的分代收集器工作策略类似。对象在新域中分配,即JRockit文档中的nursery。这种收集器最适合单cpu机上小型堆操作。

  4.1.2.单空间并发收集器

  该收集器使用完整堆,并与背景线程共同工作。尽管这种收集器可以消除中断,但是收集器需花费较长的时间寻找死对象,而且处理应用程序时收集器经常运行。如果处理器不能应付应用程序产生的垃圾,它会中断应用程序并关闭收集。

  分代并发收集器这种收集器在护理域使用排它复制收集器,在旧域中则使用并发收集器。由于它比单空间共同发生收集器中断频繁,因此它需要较少的内存,应用程序的运行效率也较高,注意,过小的护理域可以导致大量的临时对象被扩展到旧域中。这会造成收集器超负荷运作,甚至采用排它性工作方式完成收集。

  4.1.3.并行收集器

  该收集器也停止其他进程的工作,但使用多线程以加速收集进程。尽管它比其他的收集器易于引起长时间的中断,但一般能更好的利用内存,程序效率也较高。

  默认状态下,JRockit使用分代并发收集器。要改变收集器,可使用-Xgc:,对应四个收集器分别为 gencopy,singlecon,gencon以及parallel。可使用-Xms和-Xmx设置堆的初始大小和最大值。要设置护理域,则使用- Xns:java –jrockit –Xms512m –Xmx512m –Xgc:gencon –Xns128m…尽管JRockit支持-verbose:gc开关,但它输出的信息会因收集器的不同而异。JRockit还支持memory、 load和codegen的输出。

  注意 :如果 使用JRockit JVM的话还可以使用WLS自带的console(C:\bea\jrockit81sp1_141_03\bin下)来监控一些数据,如cpu, memery等。要想能构监控必须在启动服务时startWeblogic.cmd中加入-Xmanagement参数。


5.如何从JVM中获取信息来进行调整

  -verbose.gc开关可显示gc的操作内容。打开它,可以显示最忙和最空闲收集行为发生的时间、收集前后的内存大小、收集需要的时间等。打开- xx:+ printgcdetails开关,可以详细了解gc中的变化。打开-XX: + PrintGCTimeStamps开关,可以了解这些垃圾收集发生的时间,自jvm启动以后以秒计量。最后,通过-xx: + PrintHeapAtGC开关了解堆的更详细的信息。为了了解新域的情况,可以通过-XX:=PrintTenuringDistribution开关了解获得使用期的对象权。

6.Pdm系统JVM调整

  6.1.服务器:前提内存1G 单CPU

  可通过如下参数进行调整:-server 启用服务器模式(如果CPU多,服务器机建议使用此项)

  -Xms,-Xmx一般设为同样大小。 800m

  -Xmn 是将NewSize与MaxNewSize设为一致。320m

  -XX:PerSize 64m

  -XX:NewSize 320m 此值设大可调大新对象区,减少Full GC次数

  -XX:MaxNewSize 320m

  -XX:NewRato NewSize设了可不设。

  -XX: SurvivorRatio

  -XX:userParNewGC 可用来设置并行收集

  -XX:ParallelGCThreads 可用来增加并行度

  -XXUseParallelGC 设置后可以使用并行清除收集器

  -XX:UseAdaptiveSizePolicy 与上面一个联合使用效果更好,利用它可以自动优化新域大小以及救助空间比值

  6.2.客户机:通过在JNLP文件中设置参数来调整客户端JVM

  JNLP中参数:initial-heap-size和max-heap-size

  这可以在framework的RequestManager中生成JNLP文件时加入上述参数,但是这些值是要求根据客户机的硬件状态变化的(如客户机的内存大小等)。建议这两个参数值设为客户机可用内存的60%(有待测试)。为了在动态生成JNLP时以上两个参数值能够随客户机不同而不同,可靠虑获得客户机系统信息并将这些嵌到首页index.jsp中作为连接请求的参数。

  在设置了上述参数后可以通过Visualgc 来观察垃圾回收的一些参数状态,再做相应的调整来改善性能。一般的标准是减少fullgc的次数,最好硬件支持使用并行垃圾回收(要求多CPU)。