从事java开发以来,我的代码里从来只有 if 和for,今天就来记录本人遇到大神使用的反射的场景之一简易ioc的实现
本人工作使用的是JFinal,一个轻量型的框架,我见到的这套架构,三层都是用JFinal统一管理,Controller和dao层不用说了,肯定是servelt 和jdbc的封装,现在我们要看的是service业务层,
这套框架利用自定义注解加反射,自己构造出类似spring的ioc .
首先定义一个service注解
/** * Service注解,单例实体 * */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Service { }
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; 定义注入注解 /** * controller中属性注入标志 * */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Injection { }
接着在项目启动的时候,通过插件初始化,先扫包,拿到该包下面的所有带@Service注解的类,并实例化,
然后通过反射,拿到类里属性,然后给带@Injection的属性,注入实例化的对象。整个ioc就完成了
package com.jwebplat.plugins.ioc; import com.jfinal.kit.StrKit; import com.jwebplat.util.PropertiesKit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.FileFilter; import java.net.URL; import java.net.URLDecoder; import java.util.Enumeration; import java.util.HashSet; import java.util.Set; /** * */ public class ClassUtil { private static final Logger logger = LoggerFactory.getLogger(ClassUtil.class); /** * 指定basePackage下的所有Bean集合 */ private static final Set<Class<?>> Bean_SET; static { String basePackage = PropertiesKit.me().loadPropertyFile("ioc.properties").getProperty("basePackage"); Bean_SET = ClassUtil.getPackageClassSet(basePackage); } /** * 或者指定包下所有类 * @param basePackage * @return */ public static Set<Class<?>> getPackageClassSet(String basePackage) { Set<Class<?>> classSet = new HashSet<Class<?>>(); try { Enumeration<URL> urls = Thread.currentThread().getContextClassLoader().getResources(basePackage.replace(".", "/")); while (urls.hasMoreElements()) { URL url = urls.nextElement(); if(url != null) { //String packagePath = url.getPath().replaceAll("%20",""); this is a bug String packagePath = URLDecoder.decode(url.getPath(), "UTF-8"); addClass(classSet, packagePath, basePackage); } } } catch (Exception e) { logger.error("get packageAllClass fail", e); throw new RuntimeException(e); } return classSet; } public static Set<Class<?>> getBeanSet() { return Bean_SET; } /** * add class * @param classSet 集合 * @param packagePath 包路径 * @param packageName 包名 */ private static void addClass(Set<Class<?>> classSet, String packagePath, String packageName) { File[] files = new File(packagePath).listFiles(new FileFilter() { public boolean accept(File file) { return (file.isFile() && file.getName().endsWith(".class")) || file.isDirectory(); } }); if ( files == null ) { return; } for(File file : files) { String fileName = file.getName(); if(file.isFile()) { String className = fileName.substring(0, fileName.lastIndexOf(".")); if(StrKit.notBlank(packageName)){ className = packageName+"."+className; } doAddClass(classSet, className); }else { String subPackagePath = fileName; if(StrKit.notBlank(packagePath)) { subPackagePath = packagePath+"/"+fileName; } String subPackageName = fileName; if(StrKit.notBlank(packageName)) { subPackageName = packageName + "." +fileName; } addClass(classSet,subPackagePath,subPackageName); } } } /** * 添加class * @param classSet * @param className */ private static void doAddClass(Set<Class<?>> classSet, String className) { Class<?> clazz = loadClass(className,false); if(clazz.isAnnotationPresent(Service.class) || clazz.isAnnotationPresent(Component.class)) { classSet.add(clazz); } } /** * 加载指定类 * @param className 类名 * @param isInit 是否必须初始化 * @return */ public static Class<?> loadClass(String className, boolean isInit) { Class<?> clazz; try { clazz = Class.forName(className, isInit, Thread.currentThread().getContextClassLoader()); } catch (ClassNotFoundException e) { logger.error("load class fail",e); throw new RuntimeException(e); } return clazz; } /** * 实例化指定class * @param clazz * @return */ public static Object newInstance(Class<?> clazz) { Object instance = null; try { instance = clazz.newInstance(); } catch (Exception e) { logger.error("new instance fail", e); } return instance; } }
public class BeanUtil { private static final Logger logger = LoggerFactory.getLogger(BeanUtil.class); private static final Map<String,Object> BEAN_MAP = new HashMap<String, Object>(); /** * bean实例化 */ public static void initInstance() { Set<Class<?>> beanSet = ClassUtil.getBeanSet(); for (Class<?> clazz : beanSet) { Object obj = null; if(clazz.isAnnotationPresent(Service.class)) { obj = Enhancer.enhance(clazz); }else { obj = ClassUtil.newInstance(clazz); } BEAN_MAP.put(clazz.getSimpleName(), obj); } } /** * init bean集合 * @return */ public static void init() { try { initInstance(); Set<Class<?>> beanSet = ClassUtil.getBeanSet(); for (Class<?> clazz : beanSet) { //为bean注入属性 Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { Object value = null; String fieldName = field.getName(); String className = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); if (field.isAnnotationPresent(Injection.class)) { try { value = BeanUtil.getBean(className); if (value == null) { for (String key : BEAN_MAP.keySet()) { if (field.getType().isAssignableFrom(BeanUtil.getBean(key).getClass())) { value = BeanUtil.getBean(key); } } } field.setAccessible(true); field.set(BEAN_MAP.get(clazz.getSimpleName()), value); } catch (Exception e) { logger.error(clazz.getName() + "注入" + className + "属性失败!", e); } } } } } catch (Exception e) { logger.info("init bean map fail",e); throw new RuntimeException(e); } } /** * 获取指定class的bean实体 * @param name * @return */ public static Object getBean(String name) { return BEAN_MAP.get(name); } public static Map<String, Object> getBeanMap() { return BEAN_MAP; } }
这位大神虽然写的单例的实例化,但是让我这种没见到的人的,不由得觉得眼前一亮,反射还能这样用,也可以大概明白spring的ioc的原理,当然spring的ioc不会这样简单,肯定封装的更好。等我有更深入的了解后,在做分享