自己写的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. codeforces 477D

    题意:给定一个长度<=5000的二进制字符串S,以及一个初始为0的n,有一下两种操作: 1. 输出n(n>=1并且为2进制形式输出) 2.n=n+1 每次选择一种操作.. 求:1.有多少方 ...

  2. SRM470

    250pt 给定1个最多16颜色的字符串(颜色可以重复),甲在最左边,乙在最右边.轮流操作,每次可以消除一种颜色. 给定一个k,问谁能最先消除完到位置k之间的障碍. 思路: 每个人肯定优先取对方没有的 ...

  3. 查询指定网段可用IP脚

    方法一:linux命令 1.fping安装: yum install fping 2.fping使用: fping -g ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ...

  4. FFmpeg4.0笔记:file2rtmp

    Github: https://github.com/gongluck/FFmpeg4.0-study.git #include <iostream> using namespace st ...

  5. C#常用修饰符

    访问修饰符 访问修饰符是一些关键字,用于指定声明的成员或类型的可访问性,C#有4个访问修饰符:public.private.protected.internal,使用这些访问修饰符可以指定以下5个访问 ...

  6. Python-使用PyQT生成图形界面

    1.安装PyQT5以及QT Designer工具包 pip install PyQt5 pip install PyQt5-tools -i http://pypi.douban.com/simple ...

  7. IPv6 Can't assign requested address

    今天试了下 bind IPv6 的地址,报错  Can't assign requested address http://stackoverflow.com/questions/24780404/p ...

  8. 【环境学习】ThinkPHP5 5.0.22/5.1.29 远程代码执行漏洞

    环境保留:2019.4.4-4.10 环境搭建: 这里我使用的是:vulhub vulhub目录结构:vulhub/thinkphp/5-rcess 测试地址(开放一段时间供大家学习):http:// ...

  9. 版本控制工具git

    公司要求用git,感觉不如svn好使,还是命令行的,暂时记录一下. 服务器是在linux上可以直接安装.我是虚拟机centos6.9版本.yum install -y git 查看版本号是git -- ...

  10. java环境的配置与安装(windows、macos、linux)

    一.windows下: 1.下载jdk:https://www.oracle.com2.安装教程:https://www.cnblogs.com/zlslch/p/5658399.html 二.mac ...