Spring BeanUtils 소스 코드 분석
우리 가 자바 웹 프로젝트 에 착수 할 때
DO、VO、DTO
대상 간 의 속성 복사 본 을 자주 만 날 수 있다.만약 에get、set
의 방법 으로 값 을 부여 하면 코드 가 상당히 지루 하고 추 할 것 이다.보통 우 리 는Spring
의BeanUtils
유형 으로 속성 복사 하 는데 그 기본 원 리 는 자바 의 반사 체 제 를 통 해다음은 소스 코드 의 구체 적 인 실현 을 살 펴 보 겠 습 니 다.선행 지식
소스 코드 를 분석 하기 전에 우 리 는 먼저 아래 의 지식 점 을 복습 합 시다.
java.lang.Class 클래스
자바 에서 만물 은 모두 대상 이 고 우리 가 코드 에 쓴 모든 유형 도 대상 이 며
java.lang.Class
류 의 대상 이다.그래서 모든 유형 은 자신의 사례 대상 이 있 고 그들 자신 도Class
유형의 대상 이다.Class
류 의 구조 방법 을 살 펴 보 자.private Class(ClassLoader loader) {
// Initialize final field for classLoader. The initialization value of non-null
// prevents future JIT optimizations from assuming this final field is null.
classLoader = loader;
}
Class 클래스 의 구조 방법 은 개인 적 인 것 입 니 다.JVM 만 이 클래스 의 대상 을 만 들 수 있 기 때문에 코드 에서
new
방식 으로 Class 대상 을 표시 할 수 없습니다.그러나 우 리 는 여전히 다른 방식 으로 Class 류 의 대상 을 얻 을 수 있다.
1.클래스 의 정적 구성원 변 수 를 통 해
Class clazz = Test.class;
2.대상 을 통한 getClass()방법
Class clazz = test.getClass();
3.Class 를 통한 정적 방법 forName()
// forName
Class clazz = Class.forName("destiny.iron.api.model.Test");
기본 유형 및 포장 유형
기본 유형 과 이에 대응 하 는 포장 류 의 Class 대상 은 같 지 않다.즉
long.class != Long.class
.PropertyDescriptor 클래스
PropertyDescriptor
클래스 는 표준 형식의 자바 빈 이 액세스 기(즉 get set 방법)를 통 해 내 보 내 는 속성 을 나타 낸다.예 를 들 어 우 리 는 다음 과 같은 방식 으로 대상 의 속성 을 할당 할 수 있다.public class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
public static void main(String[] args) throws Exception {
Person test1 = new Person();
test1.setName("vvvv");
PropertyDescriptor pd = new PropertyDescriptor("name", test1.getClass());
Method setMethod = pd.getWriteMethod(); // Wirte Read
setMethod.invoke(test1, "bbbbb");
System.out.print(test1);
}
}
참조 형식
자바 에는
strong、soft、weak、phantom
네 가지 인용 유형 이 있 습 니 다.다음은 soft 인용 과 weak 인용 을 소개 합 니 다.Soft Reference
:대상 이Soft reference
에 달 할 때 시스템 에 더 많은 메모 리 를 신청 합 니 다.GC 는 직접 회수 하 는 것 이 아니 라 메모리 가 부족 할 때 회수 합 니 다.따라서 Soft reference 는 일부 캐 시 시스템 을 구축 하 는 데 적합 합 니 다.Weak Reference
:약 한 인용 강 도 는 부 드 러 운 인용 보다 약 하고 약 한 인용 과 관련 된 대상 은 다음 GC 가 발생 하기 전 까지 만 생존 할 수 있다.쓰레기 수집 기 가 작 동 할 때 현재 메모리 가 충분 하 든 상 관 없 이 약 한 참조 대상 만 회수 합 니 다.소스 코드 분석
private static void copyProperties(Object source, Object target, Class> editable, String... ignoreProperties)
throws BeansException {
// source target null,
Assert.notNull(source, "Source must not be null");
Assert.notNull(target, "Target must not be null");
// target
Class> actualEditable = target.getClass();
// editable null, target editable ,
// editable
// actualEditable editable , actualEditable
// actualEditable editable , editable
if (editable != null) {
if (!editable.isInstance(target)) {
throw new IllegalArgumentException("Target class [" + target.getClass().getName() +
"] not assignable to Editable class [" + editable.getName() + "]");
}
actualEditable = editable;
}
// PropertyDescriptor,getPropertyDescriptors
PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);
List ignoreList = (ignoreProperties != null ? Arrays.asList(ignoreProperties) : null);
for (PropertyDescriptor targetPd : targetPds) {
// set
Method writeMethod = targetPd.getWriteMethod();
// set
if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) {
// source PropertyDescriptor, getPropertyDescriptor
PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());
if (sourcePd != null) {
// get
Method readMethod = sourcePd.getReadMethod();
// set target set source get
// ClassUtils.isAssignable()
if (readMethod != null &&
ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {
try {
//get public
if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
// ,
readMethod.setAccessible(true);
}
// get
Object value = readMethod.invoke(source);
//
if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
writeMethod.setAccessible(true);
}
// get set
writeMethod.invoke(target, value);
}
catch (Throwable ex) {
throw new FatalBeanException(
"Could not copy property '" + targetPd.getName() + "' from source to target", ex);
}
}
}
}
}
}
getPropertyDescriptors
소스 코드: public static PropertyDescriptor[] getPropertyDescriptors(Class> clazz) throws BeansException {
// CachedIntrospectionResults PropertyDescriptor , forClass
CachedIntrospectionResults cr = CachedIntrospectionResults.forClass(clazz);
return cr.getPropertyDescriptors();
}
@SuppressWarnings("unchecked")
static CachedIntrospectionResults forClass(Class> beanClass) throws BeansException {
// strongClassCache :
// strongClassCache = new ConcurrentHashMap, CachedIntrospectionResults>(64);
// Class key,CachedIntrospectionResults value map,
// , ConcurrentHashMap
CachedIntrospectionResults results = strongClassCache.get(beanClass);
if (results != null) {
return results;
}
// strongClassCache , softClassCache ,softClassCache
// softClassCache = new ConcurrentReferenceHashMap, CachedIntrospectionResults>(64);
// ConcurrentReferenceHashMap Spring entry ConcurrentHashMap, soft, OOM
results = softClassCache.get(beanClass);
if (results != null) {
return results;
}
results = new CachedIntrospectionResults(beanClass);
ConcurrentMap, CachedIntrospectionResults> classCacheToUse;
// isCacheSafe beanClass classloader classloader ( )
// isClassLoaderAccepted beanClass classloader classloader classloader
if (ClassUtils.isCacheSafe(beanClass, CachedIntrospectionResults.class.getClassLoader()) ||
isClassLoaderAccepted(beanClass.getClassLoader())) {
classCacheToUse = strongClassCache;
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Not strongly caching class [" + beanClass.getName() + "] because it is not cache-safe");
}
classCacheToUse = softClassCache;
}
// classloader ,
CachedIntrospectionResults existing = classCacheToUse.putIfAbsent(beanClass, results);
return (existing != null ? existing : results);
}
isAssignable
소스 코드: public static boolean isAssignable(Class> lhsType, Class> rhsType) {
Assert.notNull(lhsType, "Left-hand side type must not be null");
Assert.notNull(rhsType, "Right-hand side type must not be null");
// 、 ,
if (lhsType.isAssignableFrom(rhsType)) {
return true;
}
//
if (lhsType.isPrimitive()) {
//primitiveWrapperTypeMap map,
Class> resolvedPrimitive = primitiveWrapperTypeMap.get(rhsType);
if (lhsType == resolvedPrimitive) {
return true;
}
}
else {
//
Class> resolvedWrapper = primitiveTypeToWrapperMap.get(rhsType);
if (resolvedWrapper != null && lhsType.isAssignableFrom(resolvedWrapper)) {
return true;
}
}
return false;
}
ClassUtils.isAssignable()
방법 이 확장Class isAssignableFrom()
방법 으로 곧Java
의 기본 유형 과 포장 유형 을 호 환 할 것 이다.총결산
간단 해 보 이 는
BeanUtils
도구 류 는 그 안에 포 함 된 자바 기반 의 지식 점 이 매우 많 고 유형 정보,반사,스 레 드 안전,인용 유형,클래스 로 더 등 을 포함한다.Spring
의BeanUtils
실현 에 서 는ConcurrentHashMap
캐 시 로 사용 되 었 으 며,가 져 올 때마다PropertyDescriptor
캐 시 에 직접 가서 가 져 올 수 있 으 며,매번 호출native
방법 이 필요 없 기 때문에Spring
의BeanUtils
성능 이 좋다.링크
https://segmentfault.com/a/11...
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
thymeleaf로 HTML 페이지를 동적으로 만듭니다 (spring + gradle)지난번에는 에서 화면에 HTML을 표시했습니다. 이번에는 화면을 동적으로 움직여보고 싶기 때문에 입력한 문자를 화면에 표시시키고 싶습니다. 초보자의 비망록이므로 이상한 점 등 있으면 지적 받을 수 있으면 기쁩니다! ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.