手写Spring

简单实现Spring基于注解配置

 

ComponentScan

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ComponentScan {
    String value() default "";
}

相当于component-scan 

HspSpringConfig

@ComponentScan(value = "spring.write.component")
public class HspSpringConfig {
}

替代bean.xml文件,添加@ComponentScan,获得扫描的包

AppMain

public class AppMain {
    public static void main(String[] args) {
        HspApplicationContext ioc = new HspApplicationContext(HspSpringConfig.class);
        Object userDao = ioc.getBean("userDao");
        System.out.println(userDao);
    }
}

HspApplicationContext

public class HspApplicationContext {
    private Class configClass;
    private final ConcurrentHashMap<String, Object> ioc = new ConcurrentHashMap<>();

    public HspApplicationContext(Class configClass) {
        //1、获得扫描包路径
        //得到config文件的.class类型
        this.configClass = configClass;
        //反射得到ComponentScan注解
        ComponentScan componentScan =
                (ComponentScan)configClass.getDeclaredAnnotation(ComponentScan.class);
        //获取注解的value就是扫描的包路径
        String path = componentScan.value();
        System.out.println(path);
        //spring.write.component





        //2、得到包下的所有.class
        //得到类的加载器,获取实际目录下的(out),
        ClassLoader classLoader = ClassLoader.getSystemClassLoader();

        //URL必须按照斜杠/来写
        //path = spring.write.component
        path = path.replace(".","/");
        URL resource = classLoader.getResource(path);
        System.out.println(resource);
        //file:/D:/Atest/spring/out/production/spring/spring/write/component

        //对路径下的文件进行遍历
        File file = new File(resource.getFile());
        if(file.isDirectory()) {
            File[] files = file.listFiles();
            for (File f : files) {
                //只处理.class文件(java文件)
                String fileAbsolutePath = f.getAbsolutePath();
                if(fileAbsolutePath.endsWith(".class")) {
                    System.out.println(fileAbsolutePath);
                    //D:\Atest\spring\out\production\spring\spring\write\component\UserDao.class
                    //前面已经有了path,还需要具体的类名进行反射,放入容器
                    String className = fileAbsolutePath.substring(fileAbsolutePath.lastIndexOf("\\") + 1, fileAbsolutePath.indexOf(".class"));
                    String classFullName = path.replace("/", ".") + "." + className;
                    //判断该类是不是需要注入到容器,有无注解
                    try {
                        Class<?> aClass = classLoader.loadClass(classFullName);
                        //判断该类的实例是否有注解
                        if(aClass.isAnnotationPresent(Component.class) ||
                                aClass.isAnnotationPresent(Controller.class) ||
                                aClass.isAnnotationPresent(Service.class) ||
                                aClass.isAnnotationPresent(Repository.class)) {
                            //查看是否指定了id
                            if(aClass.isAnnotationPresent(Component.class)) {
                                //只演示了Component
                                Component component = aClass.getDeclaredAnnotation(Component.class);
                                String id = component.value();
                                if(! "".endsWith(id)) {
                                    className = id;
                                }
                            }
                            //放入容器
                            Class<?> clazz = Class.forName(classFullName);
                            Object instance = clazz.newInstance();
                            //类名首字母小写存入,springframework下的工具类
                            ioc.put(StringUtils.uncapitalize(className),instance);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    public Object getBean(String name) {
        return ioc.get(name);
    }
}

Spring整体架构分析

 

没有加@Scope(value="prototype")就是单例
ioc.getBean("name"),先到BeanDefinition Map获取,未找到异常处理,
如果是单例(single)就从单例Bean Map获取
如果是多例(prototype)就创建bean对象并返回(到BeanDefinition Map中,得到Bean的clazz对象,使用反射,创建bean返回)

1、实现扫描包,得到bean的class对象

Spring基于注解配置已经写过

HspApplicationContext

public class HspApplicationContext {
    private Class configClass;
    public HspApplicationContext(Class configClass) {
        this.configClass = configClass;
        ComponentScan componentScan =
                (ComponentScan) this.configClass.getDeclaredAnnotation(ComponentScan.class);
        String path = componentScan.value();
        System.out.println(path);//com.spring.component

        ClassLoader classLoader =
                HspApplicationContext.class.getClassLoader();
        path = path.replace(".", "/");
        System.out.println(path);//com/spring/component

        URL resource =
                classLoader.getResource(path);

        File file = new File(resource.getFile());
        if(file.isDirectory()) {
            File[] files = file.listFiles();
            for (File f : files) {
                String fileAbsolutePath = f.getAbsolutePath();
                if(fileAbsolutePath.endsWith(".class")) {
                    String className = fileAbsolutePath.substring(fileAbsolutePath.lastIndexOf("\\") + 1, fileAbsolutePath.indexOf(".class"));
                    String classFullName = path.replace("/", ".") + "." + className;
                    try {
                        Class<?> clazz = classLoader.loadClass(classFullName);
                        if(clazz.isAnnotationPresent(Component.class)) {
                            System.out.println("是Spring bean【class对象】= " + clazz + " 【类名】 = " + className);
                        } else {
                            System.out.println("不是Spring bean【class对象】= " + clazz + " 【类名】 = " + className);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

2、扫描bean信息,封装到BeanDefinition对象并放入Map

增加@Scope注解来判断单例(single)或者多例(prototype)

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Scope {
    String value() default "";
}

BeanDefinition用于封装/记录Bean信息
1、单例/多例
2、多例需要动态生成,存放Bean对应的Class对象,反射生成

public class BeanDefinition {
    private String scope;
    private Class clazz;
    public String getScope() {
        return scope;
    }
    public void setScope(String scope) {
        this.scope = scope;
    }
    public Class getClazz() {
        return clazz;
    }
    public void setClazz(Class clazz) {
        this.clazz = clazz;
    }
    @Override
    public String toString() {
        return "BeanDefinition{" +
                "scope='" + scope + '\'' +
                ", clazz=" + clazz +
                '}';
    }
}

HspApplicationContext

private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap =
            new ConcurrentHashMap<>();
//单例对象类型不确定,用Object
private ConcurrentHashMap<String, Object> singletonObejcts =
            new ConcurrentHashMap<>();

如果有@Component,就放入beanDefinitionMap中

可以将1、2步写成一个方法,在构造器里调用

3、初始化bean单例池并完成getBean、createBean方法

public class HspApplicationContext {
    private Class configClass;
    private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap =
            new ConcurrentHashMap<>();
    //单例对象类型不确定,用Object
    private ConcurrentHashMap<String, Object> singletonObejcts =
            new ConcurrentHashMap<>();
    public HspApplicationContext(Class configClass) {
        //完成扫描指定包
        beanDefinitionScan(configClass);
        //遍历所有的beanDefinition对象
        Enumeration<String> keys = beanDefinitionMap.keys();
        while(keys.hasMoreElements()) {
            String beanName = keys.nextElement();
            BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
            if("singleton".equalsIgnoreCase(beanDefinition.getScope())) {
                Object bean = createBean(beanDefinition);
                singletonObejcts.put(beanName,bean);
            }
        }
        System.out.println("singletonObejcts单例池=" + singletonObejcts);
        System.out.println("beanDefinitionMap=" + beanDefinitionMap);
    }
    public void beanDefinitionScan(Class configClass) {}

    public Object createBean(BeanDefinition beanDefinition) {
        Class clazz = beanDefinition.getClazz();
        try {
            Object instance = clazz.getDeclaredConstructor().newInstance();
            return instance;
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return null;
    }
    public Object getBean(String name) {
        //判断beanName是否存在
        if(beanDefinitionMap.containsKey(name)) {
            BeanDefinition beanDefinition = beanDefinitionMap.get(name);
            if("singleton".equalsIgnoreCase(beanDefinition.getScope())) {
                return singletonObejcts.get(name);
            } else {
                return createBean(beanDefinition);
            }
        } else {
            throw new NullPointerException("没有该Bean");
        }
    }
}

4、依赖注入

增加@Autowired注解,这里只用名字来进行匹配

 

    public Object createBean(BeanDefinition beanDefinition) {
        Class clazz = beanDefinition.getClazz();
        try {
            Object instance = clazz.getDeclaredConstructor().newInstance();
            //遍历所有字段,
            for(Field field : clazz.getDeclaredFields()) {
                //是否有Autowired
                if(field.isAnnotationPresent(Autowired.class)) {
                    String name = field.getName();
                    //通过getBean获取要组装的对象
                    Object bean = getBean(name);
                    //进行组装,private需要暴破
                    field.setAccessible(true);
                    field.set(instance,bean);//将 bean 赋值给 instance 的 field
                }
            }
            return instance;
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return null;
    }

5、bean后置处理器实现

原生Spring接口InitializingBean(初始化),自己实现这个接口,完成初始化方法
接口中有afterPropertiesSet()方法,在Bean的setter方法执行完毕后,被spring容器调用,就是初始化方法

public interface InitializingBean {
    void afterPropertiesSet() throws Exception;
}

应用:选择MonsterService来实现这个接口

@Component("monsterService")
@Scope(value = "property")
public class MonsterService implements InitializingBean {
    @Autowired
    private MonsterDao monsterDao;
    public void m1() {
        monsterDao.hi();
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("monsterService初始化方法被调用");
    }
}

在创建好Bean实例后,判断是否需要初始化
容器中常用的一个方法是:根据该类是否实现了某个接口,来判断是否要执行某个业务(接口编程)

在HspApplicationContext的createBean返回instance之前加上判断是否是这个接口的子类型,是的话就执行初始化方法

判断如果返回为null,不变化
加上beanName

public Object createBean(String beanName, BeanDefinition beanDefinition) {
        Class clazz = beanDefinition.getClazz();
        try {
            Object instance = clazz.getDeclaredConstructor().newInstance();
            //遍历所有字段,
            for(Field field : clazz.getDeclaredFields()) {
                //是否有Autowired
                if(field.isAnnotationPresent(Autowired.class)) {
                    String name = field.getName();
                    //通过getBean获取要组装的对象
                    Object bean = getBean(name);
                    //进行组装,private需要暴破
                    field.setAccessible(true);
                    field.set(instance,bean);//将 bean 赋值给 instance 的 field
                }
            }
            System.out.println("======创建好实例======" + instance);
            //初始化方法前,调用before方法,可以对容器的bean实例进行处理,然后返回处理后的bean
            for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
                Object current = beanPostProcessor.postProcessBeforeInitialization(instance, beanName);
                if(current != null)
                    instance = current;
            }
            if(instance instanceof InitializingBean) {
                try {
                    ((InitializingBean) instance).afterPropertiesSet();//将instance转成InitializingBean类型,调用方法
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            //初始化方法后,调用after方法,可以对容器的bean实例进行处理,然后返回处理后的bean
            for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
                Object current = beanPostProcessor.postProcessAfterInitialization(instance, beanName);
                if(current != null)
                    instance = current;
            }
            return instance;

后置处理器接口BeanPostProcessor

对容器中的所有bean生效

public interface BeanPostProcessor {
    //bean的初始化前调用
    default Object postProcessBeforeInitialization(Object bean, String beanName) {
        return bean;
    }
    //bean的初始化后调用
    default Object postProcessAfterInitialization(Object bean, String beanName) {
        return bean;
    }
}

自己写一个类实现后置处理器,通过Component注入到容器中

实现类可以不止一个,放在Arraylist中

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

@Component
public class HspBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        System.out.println("后置处理器before()");
         return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        System.out.println("后置处理器after()");
        return bean;
    }
}

在HspApplicationContext的扫描方法中扫描Component,再判断是否实现了后置处理器接口

6、AOP机制实现 

原生Spring实现方法
A接口写方法,B类实现A接口,给B类加上@Component注入到容器
切面类加上@Component和@Aspect
B类执行后置处理器的After方法后,变成代理对象

public interface SmartAnimalable {
    float getSum(float i, float j);
    float getSub(float i, float j);
}
@Component(value = "smartDog")
public class SmartDog implements SmartAnimalable {
    public float getSum(float i, float j) {
        float res = i + j;
        System.out.println("SmartDog-getSum-res=" + res);
        return res;
    }

    public float getSub(float i, float j) {
        float res = i - j;
        System.out.println("SmartDog-getSub-res=" + res);
        return res;
    }
}
public class SmartAnimalAspect {
    public static void showBeginLog() {
        System.out.println("前置通知..");
    }
    public static void showSuccessLog() {
        System.out.println("返回通知..");
    }
}

在HspBeanPostProcessor的after方法中实现AOP(写死的方法)

public Object postProcessAfterInitialization(Object bean, String beanName) {
        System.out.println("后置处理器after()");
        if("smartDog".equals(beanName)) {
            Object proxyInstance = Proxy.newProxyInstance(HspBeanPostProcessor.class.getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    Object result = null;
                    if("getSum".equals(method.getName())) {
                        SmartAnimalAspect.showBeginLog();
                        result = method.invoke(bean,args);
                        SmartAnimalAspect.showSuccessLog();
                    } else {
                        result = method.invoke(bean,args);
                    }
                    return result;
                }
            });
            return proxyInstance;
        }
        return bean;
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值