简单实现Spring框架--注解版
自己写的Spring框架——简单实现IoC容器功能
前几天在网上看了篇帖子,是用xml的方式实现spring的ioc容器,觉得挺有意思的,这边自己试着用注解的形式造了一套轮子。
工程结构
codeing
ScopeType.java
package xyz.tmlh.type; import org.apache.commons.lang.StringUtils; /** * <p> * Description: bean的作用域 * </p> */ public enum ScopeType { /** * 原型 */ PROTOTYPE, /** * 单例 */ SINGLETON; public static ScopeType getScopt(String name){ if(StringUtils.equalsIgnoreCase(name, PROTOTYPE.toString())) { return PROTOTYPE; } return SINGLETON; } }
Bean.java
/* * $Id: Bean.java, 2019年1月15日 下午4:07:10 TianXin Exp $ * * Copyright (c) 2018 Vnierlai Technologies Co.,Ltd * All rights reserved. * * This software is copyrighted and owned by Vnierlai or the copyright holder * specified, unless otherwise noted, and may not be reproduced or distributed * in whole or in part in any form or medium without express written permission. */ package xyz.tmlh.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import xyz.tmlh.type.ScopeType; /** * <p> * Description: * </p> */ @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Bean { String name() default ""; ScopeType scope() default ScopeType.SINGLETON; }
Configuration.java
package xyz.tmlh.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * <p> * Description: 用来标注这是一个配置类 * </p> */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Configuration { String value() default ""; }
AnnotationConfigMange.java
package xyz.tmlh.config; import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.lang.StringUtils; import xyz.tmlh.annotation.Bean; import xyz.tmlh.annotation.Configuration; import xyz.tmlh.entity.Property; import xyz.tmlh.type.ScopeType; public class AnnotationConfigMange{ /** * 读取配置文件并返回读取结果 * 返回Map集合便于注入,key是每个Bean的name属性,value是对应的那个Bean对象 * @throws InvocationTargetException * @throws IllegalArgumentException * @throws IllegalAccessException */ public Map<String, xyz.tmlh.entity.Bean> getConfig(Class<?> clazz) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { Map<String, xyz.tmlh.entity.Bean> map = new HashMap<String, xyz.tmlh.entity.Bean>(); if(!isExistAnnotation(clazz.getAnnotations())) { throw new RuntimeException("not found annotation Configuration"); } //获取类中的所有方法 Method[] methods = clazz.getDeclaredMethods(); for (Method method : methods) { Bean beanMethod = method.getAnnotation(Bean.class); if(beanMethod != null) { xyz.tmlh.entity.Bean bean = new xyz.tmlh.entity.Bean(); bean.setId(method.getName()); try { Object newInstance = clazz.newInstance(); bean.setObj( method.invoke(newInstance, null)); bean.setScope(beanMethod.scope()); if(StringUtils.isEmpty(beanMethod.name())) { map.put(method.getName(), bean); }else { map.put(beanMethod.name(), bean); } } catch (InstantiationException e) { e.printStackTrace(); } } } return map; } private boolean isExistAnnotation(Annotation[] annotations){ for (Annotation annotation : annotations) { if(Configuration.class == annotation.annotationType()) { return true; } } return false; } }
接口BeanFactory继承图
BeanFactory.java
public interface BeanFactory { Object getBean(String name); <T>T getBean(Class<T> clazz) throws Exception; Object createBean(Bean bean); }
AbstractBeanFactoryHandler.java
package xyz.tmlh.support; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import xyz.tmlh.entity.Bean; import xyz.tmlh.type.ScopeType; public abstract class AbstractBeanFactoryHandler implements BeanFactory{ /** * 获得读取的配置文件中的Map信息 */ protected Map<String, Bean> map; /** * 作为IOC容器使用,放置spring放置的对象 */ protected Map<String, Object> context = new HashMap<String, Object>(); public Object createBean(Bean bean) { // 创建该类对象 Object obj = bean.getObj(); if (obj == null) { throw new RuntimeException(bean.getClassName() + "not found"); } return obj; } @Deprecated public <T>T getBean(Class<T> clazz) throws Exception { throw new RuntimeException("Please use the method getBean(String beanNme)!"); } @Deprecated public Object getBean(String name) { Object bean = context.get(name); // 如果为空说明scope不是singleton,那么容器中是没有的,这里现场创建 if (bean == null) { throw new RuntimeException("Named is " + name + " cannot be found in the ioc!"); } return bean; } }
AnnotationConfigApplicationContext.java
package xyz.tmlh.support; import java.util.Map.Entry; import org.apache.commons.beanutils.BeanUtils; import xyz.tmlh.config.AnnotationConfigMange; import xyz.tmlh.entity.Bean; import xyz.tmlh.type.ScopeType; /** * <p> * Description: 注解版启动 * </p> */ public class AnnotationConfigApplicationContext extends AbstractBeanFactoryHandler { public AnnotationConfigApplicationContext(Class<?> clazz) throws Exception { AnnotationConfigMange configManager = new AnnotationConfigMange(); // 1.读取配置文件得到需要初始化的Bean信息 map = configManager.getConfig(clazz); // 2.遍历配置,初始化Bean init(); } public void init() { for (Entry<String, Bean> en : map.entrySet()) { String beanName = en.getKey(); Bean bean = en.getValue(); Object existBean = context.get(beanName); // 当容器中为空并且bean的scope属性为singleton时 if (existBean == null && bean.getScope().equals(ScopeType.SINGLETON)) { // 根据字符串创建Bean对象 Object beanObj = createBean(bean); // 把创建好的bean对象放置到map中去 context.put(beanName, beanObj); } } } @SuppressWarnings("unchecked") public <T> T getBean(Class<T> clazz) throws Exception { T bean = null; int n = 0; for (Entry<String, Object> entry : context.entrySet()) { if (entry.getValue().getClass() == clazz) { bean = (T)entry.getValue(); n++; } } if (n == 2) { throw new RuntimeException("容器中存在多个" + clazz.getSimpleName()); } if (n == 0) { for (Entry<String, Bean> entry : map.entrySet()) { if (entry.getValue().getObj().getClass() == clazz) { if (entry.getValue().getScope().equals(ScopeType.PROTOTYPE)) { T newInstance = (T)entry.getValue().getObj().getClass().newInstance(); BeanUtils.copyProperties(newInstance, entry.getValue().getObj()); return newInstance; } return (T)entry.getValue().getObj(); } } throw new RuntimeException("ioc not found " + clazz.getName()); } return bean; } }
测试的代码就不发了
这里贴上github地址有兴趣的可以看看: https://github.com/tmlh98/start-work-series/tree/master/MySpring