實現簡單的IOC容器
阿新 • • 發佈:2020-11-20
一:Bean的定義
public interface XBeanDefinition { final static String SINGLETON = "singleton"; //單例 final static String PROTOTYPE = "prototype"; //原型 Class<?> getBeanClass(); boolean isSingleton(); boolean isPrototype(); String getInitMethodName(); }
public class GenericBeanDefinition implementsXBeanDefinition{ //初始化方法名 private String initMethodName; //類 private Class<?> clazz; //預設為單例模式 private String scope = XBeanDefinition.SINGLETON; public void setInitMethodName(String initMethodName) { this.initMethodName = initMethodName; } public Class<?> getClazz() {return clazz; } public void setClazz(Class<?> clazz) { this.clazz = clazz; } public Class<?> getBeanClass() { return this.clazz; } public boolean isSingleton() { return Objects.equals(this.scope,XBeanDefinition.SINGLETON); } publicboolean isPrototype() { return Objects.equals(this.scope,XBeanDefinition.PROTOTYPE); } public String getInitMethodName() { return null; } }
二:BeanFactory
public interface XBeanFactory { Object getBean(String beanName); }
public interface XBeanDefinitionRegistry { //註冊bean到工廠裡 void registryBeanDefinition(String beanName, XBeanDefinition beanDefinition) throws Exception ; //獲得beanDefinition XBeanDefinition getBeanDefinition(String beanName); //判斷beanDefinition boolean containBeanDefinition(String beanName); }
預設工廠
public class DefaultBeanFactory implements XBeanFactory,XBeanDefinitionRegistry{ public Map<String,Object> beanMap = new ConcurrentHashMap<>(); //模擬spring中的單例池 private Map<String,XBeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(); //儲存benadefinition @Override public void registryBeanDefinition(String beanName, XBeanDefinition beanDefinition)throws Exception { Objects.requireNonNull(beanName,"beanName不能為空"); if(beanDefinitionMap.containsKey(beanName)) { throw new Exception("已存在【"+beanName+ "】的bean定義"+getBeanDefinition(beanName)); } beanDefinitionMap.put(beanName,beanDefinition); } @Override public XBeanDefinition getBeanDefinition(String beanName) { return beanDefinitionMap.get(beanName); } @Override public boolean containBeanDefinition(String beanName) { return beanDefinitionMap.containsKey(beanName); } /** * 獲得bean * @param beanName * @return */ @Override public Object getBean(String beanName) { try { return doGetBean(beanName); } catch (Exception e) { e.printStackTrace(); } return null; } private Object doGetBean(String beanName) throws Exception { Objects.requireNonNull(beanName,"beanName不能為空"); Object instance = beanMap.get(beanName); if(instance != null) //先判斷單例池裡是否存在 { return instance; } //先獲得beanDefinition XBeanDefinition beanDefinition = beanDefinitionMap.get(beanName); Class<?> clazz = beanDefinition.getBeanClass(); //建立例項物件 instance = clazz.newInstance(); String methodName = beanDefinition.getInitMethodName(); if(null != methodName) { //通過反射執行初始化方法 Method method = clazz.getMethod(methodName, null); method.invoke(instance,null); } if(beanDefinition.isSingleton()) { beanMap.put(beanName,instance); } return instance; } }
三:定義幾個簡單的註解
@Target(ElementType.FIELD) //作用在屬性上 @Retention(RetentionPolicy.RUNTIME) @Documented public @interface XAutowired { }
@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface XBean { String value() default ""; //bean id String initMethod() default ""; //指定初始化方法名 }
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface XComponent { String value() default ""; }
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface XConfiguration { String value() default ""; }
四:啟動類
public class XSpringApplication { //預設為defaultBeanFactory private static DefaultBeanFactory beanFactory = new DefaultBeanFactory(); /** * 初始化方法 */ public static void run(String configFilePath) { //配置檔案載入到記憶體中 ConfigUtil.loadConfig(configFilePath); //獲得需要掃描的路徑 String scanPackage = ConfigUtil.contextConfig.getProperty("scan-package"); //掃描類 ScannerUtil.doScanner(scanPackage); resolve(ScannerUtil.classNameList); } //解析類,看是否有註解 private static void resolve(List<String> classNameList) { if(classNameList.isEmpty()) { return; } try { for(String className : classNameList) { Class<?> clazz = Class.forName(className); if(clazz.getDeclaredAnnotations().length != 0) //判讀當前類是否有註解 { Object instance = clazz.newInstance(); Method[] methods = clazz.getMethods();//獲得所有方法 Field[] fields = clazz.getFields();//獲取所有屬性 String beanName = ""; if(clazz.isAnnotationPresent(XComponent.class)) { beanName = clazz.getAnnotation(XComponent.class).value(); if(beanName.equals("")) //如果beanName為"" { beanName = toLowerFirstCase(clazz.getSimpleName()); } } else if(clazz.isAnnotationPresent(XConfiguration.class)) { beanName = toLowerFirstCase(clazz.getSimpleName()); } GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); beanDefinition.setClazz(clazz); //註冊bean beanFactory.registryBeanDefinition(beanName,beanDefinition); beanFactory.beanMap.put(beanName,instance); listMethod(methods,instance); //遍歷所有方法 listFields(fields,instance); //遍歷所有屬性 } } } catch (Exception e) { e.printStackTrace(); } } public static Object getBean(String beanName) { return beanFactory.getBean(beanName); } /** * 獲取類的首字母小寫的名稱 * * @param className ClassName * @return java.lang.String */ private static String toLowerFirstCase(String className) { char[] charArray = className.toCharArray(); charArray[0] += 32; return String.valueOf(charArray); } private static String getBeanName(String className) { String[] arr = className.split("\\."); return toLowerFirstCase(arr[arr.length-1]); } private static void listMethod(Method[] methods , Object instance) { try{ for(Method method : methods) //遍歷所有方法,判斷是否使用了@Bane註解 { if(method.isAnnotationPresent(XBean.class)) //判斷方法是否用XBean註解 { //獲得返回值型別 String type = method.getGenericReturnType().getTypeName(); String beanName = ""; String val = method.getAnnotation(XBean.class).value(); if(!"".equals(val)) { beanName = val; } else { beanName = getBeanName(type); } Class classN = Class.forName(type); GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); beanDefinition.setClazz(classN); beanFactory.registryBeanDefinition(beanName,beanDefinition); Object bean = method.invoke(instance, method.getParameters());//通過反射呼叫方法示例出bean beanFactory.beanMap.put(beanName,bean);//直接加入beanMap中 } } } catch (Exception e) { e.printStackTrace(); } } private static void listFields(Field[] fields , Object instance) throws Exception { for(Field field : fields) { if(!field.isAnnotationPresent(XAutowired.class)) { continue; } else { field.setAccessible(true); Class<?> aClass = field.getType(); //獲得需要注入屬性的class物件 String beanName = toLowerFirstCase(aClass.getSimpleName()); //先判斷aclass是否已經註冊 if(!beanFactory.containBeanDefinition(beanName)) { throw new Exception("該屬性物件沒有在spring容器中註冊"); } //該aclass已經註冊在spring中 //判斷spring容器中是否已經存在該aclass的示例物件,如果不存在則會例項出一個物件 Object bean = beanFactory.getBean(beanName); field.set(instance,bean);//注入屬性 } } } }
工具類
public class ConfigUtil { public static Properties contextConfig = new Properties(); /** * 載入配置檔案到記憶體中 * @param configPath 配置檔案路徑 */ public static void loadConfig(String configPath) { InputStream inputStream = ConfigUtil.class.getClassLoader().getResourceAsStream(configPath); try { contextConfig.load(inputStream); } catch (IOException e) { e.printStackTrace(); } finally { if(inputStream != null) { try { inputStream.close(); //關閉流 } catch (IOException e) { e.printStackTrace(); } } } } }
public class ScannerUtil { public static List<String> classNameList = new ArrayList<>(); /** * 掃描類 * @param scanPackage */ public static void doScanner(String scanPackage) { URL resourcePath = ScannerUtil.class.getResource("/" + scanPackage.replaceAll("\\.", "/")); if(null == resourcePath) { return ; } File classPath = new File(resourcePath.getFile()); //遍歷 for(File file : classPath.listFiles()) { if(file.isDirectory()) //資料夾則遞迴查詢 { doScanner(scanPackage+"." + file.getName()); } else { //反射判斷是否有componton註解 if(!file.getName().endsWith(".class")) { continue; } String className = (scanPackage + "." + file.getName()).replace(".class",""); classNameList.add(className); } } } }
五:測試
實體類
@XComponent(value = "user")
public class User {
private String uid;
private String userName;
public String getUid() {
return uid;
}
public void setUid(String uid) {
this.uid = uid;
}
@Override
public String toString() {
return "User{" +
"uid='" + uid + '\'' +
", userName='" + userName + '\'' +
'}';
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
測試
@XComponent
public class Test { public static void main(String[] args) { XSpringApplication.run("application.properties"); User user = (User)XSpringApplication.getBean("user"); // ConfigurationTest test = (ConfigurationTest)XSpringApplication.getBean("configurationTest"); // System.out.println(test.user); }
測試XBean,把User類註解註釋掉
@XConfiguration public class ConfigurationTest { // @XAutowired // public User user; @XBean(value = "user") public User getUser() { User user = new User(); user.setUid("123456"); user.setUserName("swq"); return user; } @XBean public Student getStudent() { return new Student(); } }
測試Autowired
@XConfiguration public class ConfigurationTest { @XAutowired public User user; @XBean(value = "user") public User getUser() { User user = new User(); user.setUid("123456"); user.setUserName("swq"); return user; } @XBean public Student getStudent() { return new Student(); } }
public class Test { public static void main(String[] args) { XSpringApplication.run("application.properties"); User user = (User)XSpringApplication.getBean("user"); System.out.println(user); ConfigurationTest test = (ConfigurationTest)XSpringApplication.getBean("configurationTest"); System.out.println(test.user); } }
application.properties
scan-package=com.swq //需要掃描的類路徑
簡單實現了一個自己的ioc容器,總體思路無非是掃描類中的註解反射實現類例項,但是對自己學習spring還是很有幫助的。下次實現簡單的aop。
感覺spring中的精髓還是很難掌握,多多學習。
https://gitee.com/swqandlili/xspring