反射使用场景记录--简易ioc的实现(小技巧)

从事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不会这样简单,肯定封装的更好。等我有更深入的了解后,在做分享

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值