自己写的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

简单实现Spring框架--注解版的更多相关文章

  1. 搭建简单的Spring框架

    1.Spring框架相关jar包下载地址http://repo.springsource.org/libs-release-local/org/springframework/spring,复制,进入 ...

  2. JavaWeb_(Spring框架)注解配置

    系列博文 JavaWeb_(Spring框架)xml配置文件  传送门 JavaWeb_(Spring框架)注解配置 传送门 Spring注解配置 a)导包和约束:基本包.aop包+context约束 ...

  3. spring mvc注解版01

    spring mvc是基于servlet实现的在spring mvc xml版中已经说过了,注解版相较于xml版更加简洁灵活. web项目的jar包: commons-logging-1.1.3.ja ...

  4. Spring 定时任务 注解版

    Task类: ManageSql.Java对应代码: package com.axb.cheney.task; import java.sql.ResultSet; import java.sql.S ...

  5. spring中整合ssm框架注解版

    和xml版差不多,只不过创建对象的方式是由spring自动扫描包名,然后命名空间多一行context代码在application.xml中,然后将每个对象通过注解创建和注入: 直接上代码: 1.use ...

  6. spring mvc简单的demo(注解版)

    tomcat配置文件:web.xml <?xml version="1.0" encoding="UTF-8"? > <web-app ver ...

  7. 课程5:Spring框架2016版视频--视频列表目录

    \day01视频\01-今天内容介绍.avi; \day01视频\02-spring的相关概念.avi; \day01视频\03-spring的ioc底层原理(一).avi; \day01视频\04- ...

  8. 菜鸟学习Spring——SpringMVC注解版前台向后台传值的两种方式

    一.概述. 在很多企业的开法中常常用到SpringMVC+Spring+Hibernate(mybatis)这样的架构,SpringMVC相当于Struts是页面到Contorller直接的交互的框架 ...

  9. 【Spring】简单的Spring AOP注解示例

    引入相关包: <properties> <spring.version>3.0.5.RELEASE</spring.version> <aspectj.ver ...

随机推荐

  1. python 引入本地module

    我们经常会遇到调用组内其他成员开发的python脚本的情况, 这时,需要借助如下代码: import sys sys.path.append('/./..') #/./.. 是需要引入的module的 ...

  2. 通过端口号查找进程号并杀掉进程window和Linux版本

    window版本: cmd下执行: 1.查找某端口号下的进程: netstat -ano|findstr 8080 如果该端口号存在进程,执行完命令后会出现列表,最后一列的数字表示该端口号下的进程号 ...

  3. iOS笔记之UIKit_UINavigationController

    //设置导航条的样式 self.navigationController.navigationBar.barStyle = UIBarStyleBlackTranslucent; //默认是白色  B ...

  4. [chrome-debug]如何使用chrome调试你的移动设备

    ### usb debug by remote chrome ### https://developer.chrome.com/devtools/docs/remote-debugging ### c ...

  5. unigui发展路线图

    unigui发展路线图 易博龙收购了SENCHA EXT JS和UNIGUI,随之官方发布了UNIGUI的发展路线图. UNIGUI是开发WEB桌面和手机移动应用的利器. UNIGUI将支持以下新特性 ...

  6. WebApi使用JWT认证

    https://www.cnblogs.com/wangyulong/p/8727683.html https://blog.csdn.net/kebi007/article/details/7286 ...

  7. Latex 表格(跨行、跨列、背景加灰)new

    一. 效果如图 二.代码如下 1. 首部增加宏包: \usepackage{multirow} 2. 正文部分增加: \begin{table} \centering \caption{Suspici ...

  8. spring项目读取配置的demo

    背景 读取配置是基础能力,研发这个模式不错,可以从不同配置中读取数据,如下图: 可以根据不同分类的文件来管理配置,然后统一在conf中配置哪些文件 package com.jwen.platform. ...

  9. C#之WinForm设置控件居中

    简单阐述 在C#的WinForm里面,原生控件是没有居中属性的,故通过重写OnResize(EventArgs e)方法,通过计算,重新定位控件位置. 以Label控件为例 (1)将label的Aut ...

  10. iOS,Android,WP, .NET通用AES加密算法

    这两天为移动App开发API,结果实现加密验证时碰到一大坑.这里不得不吐槽下又臭又硬的iOS,Windows Server无法解密出正确的结果,Android则可以,后来使用了通用的AES256加密算 ...