블로그글검색 BeanUtils 성능비교 - Apache commons, Opensympho http://benelog.egloos.com/2626007 수정이력 2010.06.21 EP님의지적으로 Apache commons Beanutils에서도 PropertyUtils.getPropertyDescriptor를사용한방식이상민님의지적으로직접 Bean의 setter를호출하는방식의자료도추가 BeanUtils.populate의경우다양한 type을가진 property 변환을하는등의실제로많은기능을수행함을 조사내용 getter, setter가있는 Java Bean들의 property들을복사할때 apache commons beanutils(http://com 이쓰이고있습니다. 그리고 Spring이나 Opensympony 쪽에도간단한 BeanUtils가따로있습니다. Spring BeanUtils : http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframewo Opensymphony BeanUtils : http://www.opensymphony.com/oscore/api/com/opensymphony/util/ 이러한 BeanUtils들은 reflection을내부적으로쓰고있으니성능이안좋을것이라는우려를할수있습성을위해서희생할수있는경우도많습니다. 그런데, 유사한용도로 Bean복사를하더라도 Apache com 다는소문은있고아래자료에의하면 100k byte object를다룰때는 Spring의 beanutils에비하면거의알려져있습니다. http://www.christianschenk.org/blog/java-bean-mapper-performance-tests/ 이는 commons BeanUtils가단순히 bean을복사하는것보다는많은기능을가진상위수준의라이브러니다. Spring이나 Opensymphony의 BeanUtils는단순히 Bean간의데이터복사, 속성정보를얻어오는정는 DynaBean 등보다넓은개념들을확장해서제공하고있습니다. 그리고 BeanUtils.populate는복사하려우에도복사를해주는등, 더확장된기능을제공하고있습니다. ( 첨부한소스의 BeanConverterTypeCo 으로들어간속성이 Bean에는 Integer, BigDecimal로선언되어있을때, BeanUtils.populate는제대로복사그렇다면 type이일치하는단순한 Bean간의복사등에는굳이 apache commons beanutils까지사용할 아래에서는 List<Map>->List<Bean> 로변환을시켜주는기능을각각의 library 로구현해서성능비교를해 형태로첨부파일에들어가있습니다. 비교군은아래와같습니다. By Hand : 직접 map.get 과 bean 의 setter 를이용해서복사 1 of 9 2015. 1. 5. 오후 6:28
Spring(property descriptor) : Spring의 BeanUtils.getPropertyDescriptors를사용. Spring의 BeanUtils에사해주는메소드가 01/05 없어서 PM 이 6:22 방식을이용했습니다. Apache Commons(property descriptor) : 2번과같은방식을사용하고, 라이브러리만 Apache common 허니버터칩의 PropertyUtils.getPropertyDescriptor를사용이지연 Apache Commons(populate) : Apache comons BeanUtils의 BeanUtils.populate 메소드를사용백화점모녀 OpenSymphony(setValues) : Opensymphony의 BeanUtils.setValues를사용이병헌디스패치문채원1 만번부터 10만번까지변환갯수를늘여주면서 (X축), 밀리세컨트단위로간단히수행시간 (Y축) 을측정이승기김무열킬미힐미황정음 Opensymphony 쪽이너무많이차이가나서제외하고나머지 4 개만다시그려봤습니다. 2 of 9 2015. 1. 5. 오후 6:28
01/05 PM 6:22 허니버터칩이지연백화점모녀이병헌디스패치문채원이승기김무열킬미힐미황정음 결론 19개의속성을가진 Bean을대상으로했을때, Map->Bean 변환의 10만건의경우순위는아래와같았 By Hand > Spring(property descriptor) = Apache Commons(property descriptor) > Apache Commo OpenSymphony(setValues) 직접손으로한것이 Sprng BeanUtils나 Commons의 PropertyUtils로 propery descriptor를통해호출한그리고 PropertyDescriptor를활용한방식들이그다음순위로, 비슷한실행속도가나왔습니다. Spring CachedIntrospectionResults라는클래스에저장을해두고있습니다. 그리고 Apache commons의 Prope 3 of 9 2015. 1. 5. 오후 6:28
PropertyUtilsBean안에 descriptorscache라는속성으로 Bean정보를 Cache하고있습니다. 그래서실행속 01/05 PM 6:22 Apache commons BeanUtils.populate는 2,3위순위의 Property descriptor를활용한것들보다 6배정허니버터칩이지연 BeanUtils.populate가더느린이유는두가지로분석이됩니다. 백화점모녀위에서말한것처럼좀더확장된 type변환을지원함. 이병헌PropertyDescriptor의배열을순회하는방식이아닌, Map의 keyset을순회하는방식을쓰고있는데, 아무디스패치 문채원이승기김무열킬미힐미 Iterator names = properties.keyset().iterator(); while (names.hasnext()) { // Identify the property name and value(s) to be assigned String name = (String) names.next(); 황정음 Object value = properties.get(name); // Perform the assignment for this property setproperty(bean, name, value); Opensymphony쪽은 70배이상더느린데, 제가구현한방식이문제가있는건지도모르겠습니다. 아뭏든위의결과를봐서는되도록성능이민감한곳에는직접 setter를호출해서복사를하고, BeanU 않다면 Spring의 BeanUtils나 Apache commons PropertyUtils를통해캐쉬된 PropertyDescriptor를정보는유리하다는것을알수있습니다. 소스 Download: beanutils.zip Apache commons BeanUtiills : BeanUtiills.popullate 활용 public <T extends Map<String,Object>, C> List<C> convertmaptobean(list<t> list, Class<C> clazz) { List<C> beanlist = new ArrayList<C>(); for (T item : list) { C bean = null; try { bean = clazz.newinstance(); BeanUtils.populate(bean, item); catch (InstantiationException e) { new IllegalArgumentException("Cannot initiate class",e); catch (IllegalAccessException e) { 4 of 9 2015. 1. 5. 오후 6:28
허니버터칩 new IllegalStateException("Cannot access the property",e); catch (InvocationTargetException 01/05 PM 6:22 e) { new IllegalArgumentException(e); 이지연백화점모녀이병헌디스패치문채원이승기김무열Apache commons BeanUtiills : PropertyUtiills.getPropertyDescriiptors 활용킬미힐미 public <T extends Map<String, Object>, C> List<C> convertmaptobean( 황정음 List<T> list, Class<C> clazz) { List<C> beanlist = new ArrayList<C>(); bean = clazz.newinstance(); PropertyDescriptor[] targetpds = PropertyUtils.getPropertyDescriptors(clazz); for (PropertyDescriptor desc : targetpds) { Object value = source.get(desc.getname()); Method writemethod = desc.getwritemethod(); if (writemethod!= null) { writemethod.invoke(bean, new Object[] { value ); catch (InstantiationException e) { new IllegalArgumentException("Cannot initiate class",e); catch (IllegalAccessException e) { new IllegalStateException("Cannot access the property",e); catch (InvocationTargetException e) { new IllegalArgumentException(e); beanlist.add(bean); return beanlist; 5 of 9 2015. 1. 5. 오후 6:28
01/05 PM 6:22 OpenSymphony BeanUtiills : setvallues 활용허니버터칩이지연 public <T extends Map<String, Object>, C> List<C> convertmaptobean( 백화점모녀 List<T> list, Class<C> targetclass) { List<C> beanlist = new ArrayList<C>(); 이병헌 for (Map<String, Object> map : list) { 디스패치문채원 이승기김무열킬미힐미황정음 bean = targetclass.newinstance(); BeanUtils.setValues(bean, map, null); catch (InstantiationException e) { new IllegalArgumentException("Cannot initiate class", e); catch (IllegalAccessException e) { new IllegalStateException("Cannot access the property", e); Spriing BeanUtiills : getpropertydescriiptors 활용 public <T extends Map<String, Object>, C> List<C> convertmaptobean( List<T> list, Class<C> clazz) { List<C> beanlist = new ArrayList<C>(); for (Map<String, Object> source : list) { C bean = tobean(source, clazz); beanlist.add(bean); return beanlist; private <C> C tobean(map<string, Object> source, Class<C> targetclass) { C bean = null; try { bean = targetclass.newinstance(); PropertyDescriptor[] targetpds = BeanUtils.getPropertyDescriptors(targetClass); for (PropertyDescriptor desc : targetpds) { Object value = source.get(desc.getname()); 6 of 9 2015. 1. 5. 오후 6:28
허니버터칩 이지연 Method 01/05 writemethod PM 6:22= desc.getwritemethod(); if (writemethod!= null) { writemethod.invoke(bean, new Object[] { value ); 백화점모녀 이병헌 디스패치문채원이승기김무열킬미힐미황정음 catch (InstantiationException e) { new IllegalArgumentException("Cannot initiate class",e); catch (IllegalAccessException e) { new IllegalStateException("Cannot access the property",e); catch (InvocationTargetException e) { new IllegalArgumentException(e); public void testapachecommonsbeanutils() { BeanConverter converter = new ApacheCommonsBeanUtilsBeanConverter(); @Test public void testapachecommonspropertyutils() { BeanConverter converter = new ApacheCommonsPropertyUtilsBeanConverter(); @Test public void testopensymphony() { BeanConverter converter = new OpenSymphonyBeanConverter(); @Test public void testspring() { BeanConverter converter = new SpringBeanConverter(); 7 of 9 2015. 1. 5. 오후 6:28
허니버터칩 이지연 public void 01/05 testbyhand() PM 6:22 { BeanConverter converter = new UserConverter(); 백화점모녀 이병헌디스패치문채원이승기김무열킬미힐미황정음 private void excuectebeanconverter(beanconverter converter, int iterations) { List<Map<String, Object>> testlist = createmaplistfortest(iterations); long start = System.currentTimeMillis(); List<User> beanlist = converter.convertmaptobean(testlist, User.class); long end = System.currentTimeMillis(); System.out.printf("%s,%d times, %d milliseconds \r\n", converter.getclass().getsimplename(), iterations, (end - start)); private void executeincrementally(beanconverter converter) { for (int i = 0; i <= 100000; i += 10000) { excuectebeanconverter(converter, i); private List<Map<String, Object>> createmaplistfortest(int iterations) { List<Map<String, Object>> list = new ArrayList<Map<String, Object>>(); Map<String, Object> user = new HashMap<String, Object>(); user.put("name", " 내이름 "); user.put("name1", " 내이름 "); user.put("name2", " 내이름 "); user.put("name3", " 내이름 "); user.put("name4", " 내이름 "); user.put("name5", " 내이름 "); user.put("name6", " 내이름 "); user.put("name7", " 내이름 "); user.put("name8", " 내이름 "); user.put("name9", " 내이름 "); user.put("name10", " 내이름 "); user.put("income", new BigDecimal("1000100100")); user.put("address", " 오늘아침내가행복한이유는이런거지오늘아침내가서러운이유는그런 user.put("introduce", " 오늘아침내가행복한이유는이런거지오늘아침내가서러운이유는그 user.put("married", true); user.put("nickname", " 뻐꾸기 "); for (int i = 0; i < iterations; i++) { 8 of 9 2015. 1. 5. 오후 6:28
01/05 PM 6:22 허니버터칩이지연백화점모녀이병헌디스패치문채원이승기 김무열 2010.06.17 21:35 킬미힐미 황정음 오우정말감사합니다. 꼭필요한자료 이용약관개인정보취급방침청소년보호정책고객센터공지사항 ZUM 9 of 9 2015. 1. 5. 오후 6:28