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

    使用PM2将Node.js的集群变得更加容易(http://www.cnblogs.com/jaxu/p/5193643.html) nodejs pm2配置使用教程(http://blog.csdn ...

  2. HyperServer 中的 SSL 支持

    HyperServer 中的 SSL 支持 DLL 模式不需要 SSL 配置, 因为 web 服务器 (如 IIS) 将承担 ssl 配置和 ssl 证书的责任. 对于独立和服务模式, ssl 配置是 ...

  3. Android-Java-等待唤醒机制原理

    儿时的游戏:(等待 与 唤醒) 有一群小朋友一起玩一个游戏,这个游戏可能大家都玩过,大家一起划拳,划拳输得最惨的那个小朋友去抓人(这个小朋友取名为 CPU),被抓的很多人取名为线程,有很多线程,如果其 ...

  4. scrapy中Request中常用参数

    url: 就是需要请求,并进行下一步处理的url callback: 指定该请求返回的Response,由那个函数来处理. method: 一般不需要指定,使用默认GET方法请求即可 headers: ...

  5. Linux环境GitLab安装与配置

    1.背景 近期公司源代码管理工具从svn转向git,因此要在服务器上部署gitlab,总共部署了两台服务器,一台是Ubuntu server 17.04,一台是Centos7.在部署的过程中遇到不少问 ...

  6. [宁波集训]0827Day1

    1.\(CF771D\ Bear\ and\ Company\)(原题,比赛时改为多组数据) 一道毒瘤\(dp\)题,\(dp[i][j][k][0/1]\)表示有\(i\)个\(V\),有\(j\) ...

  7. jQuery基础(3)- ajax

    一.jQuery的ajax 1.什么是ajax AJAX = 异步的javascript和XML(Asynchronous Javascript and XML). 简言之,在不重载整个网页的情况下, ...

  8. POJ 2442(优先队列 k路归并 堆)

    Description Given m sequences, each contains n non-negative integer. Now we may select one number fr ...

  9. Android逆向——smali复杂类解析

    i春秋作家:HAI_ 之前在Android逆向——初识smali与java类中讲解了基本的HelloWorld和简单类.这节课就要进一步深入.如果能够耐下心来分析一定会有所收获.——写给自己和后来人. ...

  10. Shell - 简明Shell入门13 - 用户输入(UserInput)

    示例脚本及注释 1 - arguments #!/bin/bash if [ -n "$1" ];then # 验证参数是否传入 echo "The first para ...