001/** 002 * Copyright (c) 2015-2022, Michael Yang 杨福海 (fuhai999@gmail.com). 003 * <p> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package io.jboot.utils; 017 018import com.jfinal.aop.Aop; 019import com.jfinal.log.Log; 020import io.jboot.aop.annotation.StaticConstruct; 021import io.jboot.exception.JbootException; 022 023import java.lang.reflect.*; 024import java.util.Arrays; 025import java.util.Map; 026import java.util.concurrent.ConcurrentHashMap; 027 028/** 029 * 类实例创建者创建者 030 * Created by michael on 17/3/21. 031 */ 032public class ClassUtil { 033 034 private static Log LOG = Log.getLog(ClassUtil.class); 035 036 private static final Map<Class<?>, Object> singletons = new ConcurrentHashMap<>(); 037 038 039 /** 040 * 获取单例 041 * 042 * @param clazz 043 * @param <T> 044 * @return 045 */ 046 public static <T> T singleton(Class<T> clazz) { 047 return singleton(clazz, true); 048 } 049 050 051 /** 052 * 获取单利 053 * 054 * @param clazz 055 * @param createByAop 056 * @param <T> 057 * @return 058 */ 059 public static synchronized <T> T singleton(Class<T> clazz, boolean createByAop) { 060 Object ret = singletons.get(clazz); 061 if (ret == null) { 062 ret = newInstance(clazz, createByAop); 063 if (ret != null) { 064 singletons.put(clazz, ret); 065 } else { 066 LOG.error("Can not new instance for class: " + clazz.getName()); 067 } 068 } 069 return (T) ret; 070 } 071 072 public static synchronized <T> T singleton(Class<T> clazz, boolean createByAop, boolean inject) { 073 Object ret = singletons.get(clazz); 074 if (ret == null) { 075 ret = newInstance(clazz, createByAop); 076 if (ret != null) { 077 if (inject && !createByAop) { 078 Aop.inject(ret); 079 } 080 singletons.put(clazz, ret); 081 } else { 082 LOG.error("Can not new instance for class: " + clazz.getName()); 083 } 084 } 085 return (T) ret; 086 } 087 088 /** 089 * 创建新的实例 090 * 091 * @param <T> 092 * @param clazz 093 * @return 094 */ 095 public static <T> T newInstance(Class<T> clazz) { 096 return newInstance(clazz, true); 097 } 098 099 100 /** 101 * 创建新的实例,并传入初始化参数 102 * 103 * @param clazz 104 * @param paras 105 * @param <T> 106 * @return 107 */ 108 public static <T> T newInstance(Class<T> clazz, Object... paras) { 109 return newInstance(clazz, true, paras); 110 } 111 112 113 /** 114 * 是否通过 AOP 来实例化 115 * 116 * @param clazz 117 * @param createByAop 118 * @param <T> 119 * @return 120 */ 121 public static <T> T newInstance(Class<T> clazz, boolean createByAop) { 122 if (createByAop) { 123 return Aop.get(clazz); 124 } else { 125 try { 126 Constructor constructor = clazz.getDeclaredConstructor(); 127 constructor.setAccessible(true); 128 return (T) constructor.newInstance(); 129 } catch (Exception e) { 130 LOG.error("Can not new instance for class:" + clazz.getName() + "\n" + e, e); 131 } 132 133 return null; 134 } 135 } 136 137 138 public static <T> T newInstance(Class<T> clazz, boolean createByAop, Object... paras) { 139 try { 140 Constructor<?>[] constructors = clazz.getDeclaredConstructors(); 141 for (Constructor<?> constructor : constructors) { 142 if (isConstructorMatchedParas(constructor, paras)) { 143// constructor.setAccessible(true); 144 Object ret = constructor.newInstance(paras); 145 if (createByAop) { 146 Aop.inject(ret); 147 } 148 return (T) ret; 149 } 150 } 151 152 throw new IllegalArgumentException("Can not matched constructor by paras" + Arrays.toString(paras) + " for class: " + clazz.getName()); 153 } catch (Exception e) { 154 LOG.error("Can not new instance for class: " + clazz.getName() + "\n" + e, e); 155 } 156 157 return null; 158 } 159 160 161 private static boolean isConstructorMatchedParas(Constructor<?> constructor, Object[] paras) { 162 if (constructor.getParameterCount() == 0) { 163 return paras == null || paras.length == 0; 164 } 165 166 if (constructor.getParameterCount() > 0 167 && (paras == null || paras.length != constructor.getParameterCount())) { 168 return false; 169 } 170 171 Class<?>[] parameterTypes = constructor.getParameterTypes(); 172 for (int i = 0; i < parameterTypes.length; i++) { 173 Class<?> parameterType = parameterTypes[i]; 174 Object paraObject = paras[i]; 175 if (paraObject != null && !parameterType.isAssignableFrom(paraObject.getClass())) { 176 return false; 177 } 178 } 179 180 return true; 181 } 182 183 184 public static <T> T newInstanceByStaticConstruct(Class<T> clazz) { 185 StaticConstruct staticConstruct = clazz.getAnnotation(StaticConstruct.class); 186 if (staticConstruct == null) { 187 return null; 188 } 189 190 return newInstanceByStaticConstruct(clazz, staticConstruct); 191 } 192 193 194 public static <T> T newInstanceByStaticConstruct(Class<T> clazz, StaticConstruct staticConstruct) { 195 196 Method method = getStaticConstruct(staticConstruct.value(), clazz); 197 198 if (method == null) { 199 throw new JbootException("Can not new instance by static construct for class: " + clazz.getName()); 200 } 201 202 try { 203 return (T) method.invoke(null, null); 204 } catch (Exception e) { 205 206 LOG.error("Can not invoke method: " + method.getName() 207 + " in class: " + clazz.getName() + "\n" + e, e); 208 209 if (e instanceof RuntimeException) { 210 throw (RuntimeException) e; 211 } else { 212 throw new RuntimeException(e); 213 } 214 } 215 } 216 217 218 private static Method getStaticConstruct(String name, Class<?> clazz) { 219 Method[] methods = clazz.getDeclaredMethods(); 220 for (Method method : methods) { 221 if (Modifier.isStatic(method.getModifiers()) 222 && Modifier.isPublic(method.getModifiers()) 223 && method.getReturnType() == clazz) { 224 if (StrUtil.isBlank(name)) { 225 return method; 226 } else if (name.equals(method.getName())) { 227 return method; 228 } 229 } 230 } 231 return null; 232 } 233 234 /** 235 * 创建新的实例 236 * 237 * @param <T> 238 * @param clazzName 239 * @return 240 */ 241 public static <T> T newInstance(String clazzName) { 242 return newInstance(clazzName, true); 243 } 244 245 /** 246 * 创建新的实例 247 * 248 * @param <T> 249 * @param clazzName 250 * @return 251 */ 252 public static <T> T newInstance(String clazzName, boolean createByAop) { 253 return newInstance(clazzName, createByAop, Thread.currentThread().getContextClassLoader()); 254 } 255 256 257 /** 258 * 创建新的实例 259 * 260 * @param clazzName 261 * @param createByAop 262 * @param classLoader 263 * @param <T> 264 * @return 265 */ 266 public static <T> T newInstance(String clazzName, boolean createByAop, ClassLoader classLoader) { 267 try { 268 Class<T> clazz = (Class<T>) Class.forName(clazzName, false, classLoader); 269 return newInstance(clazz, createByAop); 270 } catch (Exception e) { 271 LOG.error("Can not new instance for class: " + clazzName + "\n" + e.toString(), e); 272 } 273 274 return null; 275 } 276 277 278 private static final String ENHANCER_BY = "$$EnhancerBy"; 279 private static final String JAVASSIST_BY = "_$$_"; 280 281 public static Class getUsefulClass(Class<?> clazz) { 282 //ControllerTest$ServiceTest$$EnhancerByGuice$$40471411#hello 283 //com.demo.blog.Blog$$EnhancerByCGLIB$$69a17158 284 //io.jboot.test.app.TestAppListener_$$_jvstb9f_0 by:javassist 285 286 final String name = clazz.getName(); 287 if (name.contains(ENHANCER_BY) || name.contains(JAVASSIST_BY)) { 288 return clazz.getSuperclass(); 289 } 290 291 return clazz; 292 } 293 294 295 public static ClassType getClassType(Type type, Class<?> runClass) { 296 if (type instanceof Class) { 297 return new ClassType((Class<?>) type); 298 } 299 300 // 泛型定义在参数里,例如 List<String> 301 else if (type instanceof ParameterizedType) { 302 ClassType classType = new ClassType((Class<?>) ((ParameterizedType) type).getRawType()); 303 304 Type[] actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments(); 305 ClassType[] genericTypes = new ClassType[actualTypeArguments.length]; 306 for (int i = 0; i < actualTypeArguments.length; i++) { 307 genericTypes[i] = getClassType(actualTypeArguments[i], runClass); 308 } 309 310 classType.setGenericTypes(genericTypes); 311 return classType; 312 } 313 314 //泛型定义在 class 里,例如 List<T>,其中 T 是在 class 里的参数 315 else if (type instanceof TypeVariable && runClass != null) { 316 Type variableRawType = getTypeInClassDefined(runClass, ((TypeVariable<?>) type)); 317 if (variableRawType != null) { 318 return getClassType(variableRawType, runClass); 319 } else { 320 return null; 321 } 322 } 323 324 return null; 325 } 326 327 328 private static Type getTypeInClassDefined(Class<?> runClass, TypeVariable<?> typeVariable) { 329 Type type = runClass.getGenericSuperclass(); 330 if (type instanceof ParameterizedType) { 331 Type[] typeArguments = ((ParameterizedType) type).getActualTypeArguments(); 332 if (typeArguments.length == 1) { 333 return typeArguments[0]; 334 } else if (typeArguments.length > 1) { 335 TypeVariable<?>[] typeVariables = typeVariable.getGenericDeclaration().getTypeParameters(); 336 for (int i = 0; i < typeVariables.length; i++) { 337 if (typeVariable.getName().equals(typeVariables[i].getName())) { 338 return typeArguments[i]; 339 } 340 } 341 } 342 } 343 return null; 344 } 345 346 347 public static String buildMethodString(Method method) { 348 StringBuilder sb = new StringBuilder() 349 .append(method.getDeclaringClass().getName()) 350 .append(".") 351 .append(method.getName()) 352 .append("("); 353 354 Class<?>[] params = method.getParameterTypes(); 355 int in = 0; 356 for (Class<?> clazz : params) { 357 sb.append(clazz.getName()); 358 if (++in < params.length) { 359 sb.append(","); 360 } 361 } 362 363 return sb.append(")").toString(); 364 } 365 366 367 public static boolean hasClass(String className) { 368 try { 369 Class.forName(className, false, getClassLoader()); 370 return true; 371 } catch (ClassNotFoundException e) { 372 return false; 373 } 374 } 375 376 377 public static ClassLoader getClassLoader() { 378 ClassLoader ret = Thread.currentThread().getContextClassLoader(); 379 return ret != null ? ret : ClassUtil.class.getClassLoader(); 380 } 381 382}