基于注解实现简单Spring框架:完成IOC容器和声明式事务控制

Posted 丿涛哥哥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于注解实现简单Spring框架:完成IOC容器和声明式事务控制相关的知识,希望对你有一定的参考价值。

基于注解实现简单Spring框架:完成IOC容器和声明式事务控制

内容说明

自定义@Service、@Autowired、@Transactional注解类,完成基于注解的IOC容器(Bean对象创建及依赖注入维护)和声明式事务控制,写到转账工程中,实现异常时事务回滚。

实现原理

1.扫(项目路径下)所有的包,循环遍历所有类,使用反射获取类是否有注解@Service,如果有,则使用反射newInstance该类的实例,并将类名和类的实例存放在全局变量Map集合中。

2.如果类的属性上有@Autowired,从全局变量Map获取该属性对应的实例,使用反射技术给类的该属性赋值field.set(beanObject, object);

实现代码如下

1、自定义Service注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Service {

    String value() default "";
}

2、自定义Autowired注解

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
}

3、自定义@Transactional注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Transactional {
}

4、自定义注解解析类ApplicationContext.java

public class ApplicationContext {
    //包名
    private String packageName;
    //存储bean对象
    private Map<String, Object> beans = new HashMap<>();
    public ApplicationContext(String packageName) {
        this.packageName = packageName;
        //初始化bean对象
        initBeans();
    }

    初始化bean的方法,获取包路径下的所有class对象交给findClassAddAnnotation寻找添加了注解的类
    private void initBeans() {
        List<Class> classList = getClasses(packageName);
        findClassAddAnnotation(classList);
    }
    private List<Class> getClasses(String packageName) {
        List<Class> classList = new ArrayList<>();
        String packageDirName = packageName.replace(".", "/");
        Enumeration<URL> dirs;
        try {
            dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
            while (dirs.hasMoreElements()) {
                URL url = dirs.nextElement();
                String protocol = url.getProtocol();
                if (protocol.equals("file")) {
                    String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
                    findClasses(packageName, filePath, classList);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return classList;
    }
    
    private void findClasses(String packageName, String filePath, List<Class> classList) {
        File dir = new File(filePath);
        //选出文件夹下面所有的文件
        File[] files = dir.listFiles(new FileFilter() {
            public boolean accept(File file) {
                return (file.isDirectory() || file.getName().endsWith(".class"));
            }
        });
        for (File file : files) {
            if (file.isDirectory()) {
                findClasses(packageName + "." + file.getName(), file.getAbsolutePath(), classList);
            } else {
                String className = file.getName().substring(0, file.getName().length() - 6);
                try {
                    classList.add(Class.forName(packageName + "." + className));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    //查找添加了注解的类
    private void findClassAddAnnotation(List<Class> classList) {
        try{
            for (Class aClass : classList) {//遍历集合
                classToObjectIntoBeans(aClass, classList);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    private void classToObjectIntoBeans(Class aClass, List<Class> classList) {
        Object obj = null;
        String beanKey;
        try{
            //添加了注解才创建bean对象
            Service annotation = (Service) aClass.getAnnotation(Service.class);
            if (annotation == null){
                return;
            }
            if (!("").equals(annotation.value())){
                beanKey = annotation.value();
            }else {
                beanKey = aClass.getSimpleName();
            }
            //判断第aClass是不是接口
            if(aClass.isInterface()){
                //遍历第二个list
                for(Class implClass : classList) {
                    if (implClass.isInterface()) {//是接口跳出循环
                        continue;
                    }
                    Class fieldClassCopy = implClass.getClassLoader().loadClass(aClass.getName());
                    //判断这个类是不是这个接口下的实现类
                    if (fieldClassCopy.isAssignableFrom(implClass)) {
                        //拿到所有的构造方法
                        Constructor[] constructors = implClass.getConstructors();
                        for(Constructor constructor : constructors){//遍历
                            //参数数量
                            int parameterCount = constructor.getParameterCount();
                            //如果是无参构造,创建对象
                            if(parameterCount==0){
                                obj = constructor.newInstance();
                            }
                        }
                        break;
                    }
                }
            } else {
                //第一个参数传入的class对象不是接口,直接创建对象
                Constructor[] constructors = aClass.getConstructors();
                for(Constructor constructor : constructors){
                    int parameterCount = constructor.getParameterCount();
                    if(parameterCount==0){
                        obj = constructor.newInstance();
                    }
                }
            }
            if (obj != null) {
                //把创建好的对象放入Map
                beans.put(beanKey, obj);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    //获取bean对象
    public Object getBean(String beanName,ApplicationContext applicationContext) {
        Object beanObject = beans.get(beanName);
        try{
            referenceBindObject(beanObject);
        }catch (Exception e){
            e.printStackTrace();
        }
        Class aClass = beanObject.getClass();
        Annotation annotation = aClass.getAnnotation(Transactional.class);
        if (annotation != null) {
            ProxyFactory proxyFactory = (ProxyFactory) applicationContext.getBean("ProxyFactory", applicationContext);
            if(aClass.getInterfaces()!=null){
                beanObject = proxyFactory.getJdkProxy(beanObject);
            }else{
                beanObject = proxyFactory.getCglibProxy(beanObject);
            }

        }
        return beanObject;
    }

    private Object referenceBindObject(Object beanObject) {
        Class beanClass = beanObject.getClass();
        Field[] declaredFields = beanClass.getDeclaredFields();//获取所有属性
        try {
            for (Field field : declaredFields) {
                if (!field.isAccessible()) {
                    field.setAccessible(true);//暴力访问
                }
                Autowired filedAnnotation = field.getAnnotation(Autowired.class);
                if (filedAnnotation == null) {//如果没加注解就跳出本次循环
                    break;
                }
                Class fieldClass = field.getType();
                String classSimpleName = fieldClass.getSimpleName();//得到类的简写名称
                Object fieldObject = beans.get(classSimpleName);//通过类的简写名称再beans中获取bean
                Object object = referenceBindObject(fieldObject);
                field.set(beanObject, object);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return beanObject;
    }
}

具体业务逻辑及工具类省略。

以上是关于基于注解实现简单Spring框架:完成IOC容器和声明式事务控制的主要内容,如果未能解决你的问题,请参考以下文章

spring 的纯注解配置

Spring IoC 基于注解的开发

Spring IoC概念

全注解下的Spring IoC

全注解下的Spring IoC

Spring我抄袭了Spring,手写一套MySpring框架。。。