手撕spring框架(5)

手撕spring框架(5)

相关系列
手撕spring框架(1)
手撕spring框架(2)
手撕spring框架(3)
手撕spring框架(4)
这是本专题最后一节了,主要是讲述自定义一个注解,实现自定义值的引用,继承BeanPostProcessor接口,在对象创建的时候,注入到变量中。

注解DzendValue接口源码

package com.dzend.service;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Retention(
        java.lang.annotation.RetentionPolicy.RUNTIME
)
@Target(ElementType.FIELD)
public @interface DzendValue {
    String value() default "";
}

核心是定义一个默认值

定义DzendValueBeanPostProcessor类

package com.dzend.service;

import com.spring.BeanPostProcessor;
import com.spring.Component;

import java.lang.reflect.Field;

@Component
public class DzendValueBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {

        for (Field field : bean.getClass().getDeclaredFields()) {
            if (field.isAnnotationPresent(DzendValue.class)) {
                field.setAccessible(true);
                try{
                    field.set(bean,field.getAnnotation(DzendValue.class).value());
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }

        return bean;
    }
}

继承BeanPostProcessor接口,并实现在初始后给属性赋值。

使用

添加新的代码
在上图标出来的代码是用来实现继承了BeanPostProcessor对象,在createBean的时候,创建完对象,来执行aop这块的业务逻辑,在初始化前和初始化后。
源码:

package com.spring;

import java.beans.Introspector;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class DzendApplicationContext {

    private Class<?> configClass;

    private Map<String,BeanDefinition> beanDefinitionMap= new HashMap<>();

    private Map<String, Object> singletonObjects=new HashMap<>();

    private List<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();

    public DzendApplicationContext(Class configClass)   {
        this.configClass=configClass;

        scan(configClass);

    }

    private void scan(Class configClass) {
        if(configClass.isAnnotationPresent(ComponentScan.class)){
            ComponentScan componentScan = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
            String path = componentScan.value();
            path = path.replace(".","/");


            ClassLoader classLoader = DzendApplicationContext.class.getClassLoader();
            URL resource = classLoader.getResource(path);

            try {
                path = URLDecoder.decode(path, "UTF-8");
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e);
            }
            File file = null;
            try {
                file = new File(  URLDecoder.decode(resource.getFile(), "UTF-8"));
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e);
            }



            if(file.isDirectory()){

                for (File f : file.listFiles()) {
                    String absolutePath = f.getAbsolutePath();

                    absolutePath = absolutePath.substring(absolutePath.indexOf("com"),absolutePath.indexOf(".class"));
                    absolutePath=absolutePath.replace("\\",".");


                    try {
                        Class<?>  clazz = classLoader.loadClass(absolutePath);

                        if (clazz.isAnnotationPresent(Component.class)) {

                            if (BeanPostProcessor.class.isAssignableFrom(clazz)) {
                                BeanPostProcessor instance = (BeanPostProcessor) clazz.getConstructor().newInstance();
                                beanPostProcessorList.add(instance);
                            }


                            Component componentAnnotaion = clazz.getAnnotation(Component.class);
                            String beanName= componentAnnotaion.value();
                            if("".equals(beanName)){
                                beanName = Introspector.decapitalize(clazz.getSimpleName());
                            }

                           BeanDefinition beanDefinition = new BeanDefinition();
                            beanDefinition.setType(clazz);

                            if (clazz.isAnnotationPresent(Scope.class)) {
                                Scope scopeAnnotation = clazz.getAnnotation(Scope.class);
                                String value = scopeAnnotation.value();
                                beanDefinition.setScope(value);
                            }else{
                                beanDefinition.setScope("singleton");
                            }

                            beanDefinitionMap.put(beanName,beanDefinition);

                        }

                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        throw new RuntimeException(e);
                    } catch (InstantiationException e) {
                        throw new RuntimeException(e);
                    } catch (IllegalAccessException e) {
                        throw new RuntimeException(e);
                    } catch (NoSuchMethodException e) {
                        throw new RuntimeException(e);
                    }


                }
            }

        }
    }

    public Object getBean(String beanName){
        if(!beanDefinitionMap.containsKey(beanName)){
            throw new NullPointerException();
        }

        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if(beanDefinition.getScope().equals("singleton")){
            Object singletonObject = singletonObjects.get(beanName);

            if(singletonObject == null){
                singletonObject = createBean(beanName,beanDefinition);
                singletonObjects.put(beanName,singletonObject);
            }
            return singletonObject;
        }else{
            //原型
            Object prototypeBean = createBean(beanName, beanDefinition);
            return prototypeBean;
        }

    }

    private Object createBean(String beanName, BeanDefinition beanDefinition) {
        Class clazz = beanDefinition.getType();

        Object instance = null;


        try {
            instance = clazz.getConstructor().newInstance();


            for (Field field : clazz.getDeclaredFields()) {
                if(field.isAnnotationPresent(Autowired.class)){
                    field.setAccessible(true);
                    field.set(instance,getBean(field.getName()));
                }

            }

            if(instance instanceof BeanNameAware){
                ((BeanNameAware) instance).setBeanName(beanName);
            }

            for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
                instance = beanPostProcessor.postProcessBeforeInitialization(instance,beanName);
            }


            if(instance instanceof InitializingBean){
                ((InitializingBean) instance).afterPropertiesSet();
            }

            for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
                instance = beanPostProcessor.postProcessAfterInitialization(instance,beanName);
            }


        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }

        return instance;
    }
}

以上是最终的代码,本专题基本上讲完了一个简单的spirng框架的实现,是从0开始构建的,希望帮帮助大家对spring有一定的认识,当然,这是只是个简化版本。

  • 9
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值