模拟实现Spring IOC

通过在类上标注@Registration 注册进容器,@Injection从容器注入对象

容器类:

public class SpringContainer {

public SpringContainer(String packageToScan){

Set<Class<?>> classes = getClasses(packageToScan);

for(Class c : classes){

if(!c.isAnnotationPresent(Registration.class)) continue;

Registration annotation = (Registration) c.getAnnotation(Registration.class);

Bean bean = new Bean();

if(!"".equals(annotation.name())) {

bean.setId(annotation.name());//不是默认的就设置bean的名称

}else{

bean.setId(c.getSimpleName());//默认为类名

}

bean.setBeanClass(c);

Map<String, Class> propsMap = new HashMap<String, Class>();

//处理注入属性

Field[] props = c.getDeclaredFields();

for(Field p : props){

if(!p.isAnnotationPresent(Injection.class)) continue;

propsMap.put(p.getName(),(Class)p.getGenericType());

}

bean.setProperties(propsMap);

beanMap.put(bean.getId(), bean);

}

}

private static Map<String, Bean> beanMap = new HashMap<String, Bean>();

public static Object getBean(String beanName) throws ClassNotFoundException,

InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {

Bean bean = beanMap.get(beanName);

if (bean == null) {

throw new ClassNotFoundException();

}

Object o = bean.getBeanClass().newInstance();

Iterator<Entry<String, Class>> iter = bean.getProperties().entrySet().iterator();

while (iter.hasNext()) {

Map.Entry<String,Class> entry = iter.next();

String propName = entry.getKey();

Class propClass = entry.getValue();

setProperty(o,propName,propClass);

}

return o;

}

private static void setProperty(Object obj, String propName, Class propClass) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, ClassNotFoundException, InstantiationException {

Class<? extends Object> clazz = obj.getClass();

String methodName = returnSetMthodName(propName);

Method[] ms = clazz.getMethods();

for (Method m : ms) {

if (m.getName().equals(methodName)) {

if (m.getParameterTypes().length == 1) {

Class<?> clazzParameterType = m.getParameterTypes()[0];

if(clazzParameterType.getName().equals(propClass.getName()) ){

m.invoke(obj, getBean(propClass.getSimpleName()));

}

}

}

}

}

public static String returnSetMthodName(String fieldName){

return "set"+fieldName.substring(0,1).toUpperCase()+fieldName.substring(1);

}

/**

* 从包package中获取所有的Class

*

* @param pack

* @return

*/

public static Set<Class<?>> getClasses(String pack) {

// 第一个class类的集合

Set<Class<?>> classes = new LinkedHashSet<Class<?>>();

// 是否循环迭代

boolean recursive = true;

// 获取包的名字 并进行替换

String packageName = pack;

String packageDirName = packageName.replace(‘.‘, ‘/‘);

// 定义一个枚举的集合 并进行循环来处理这个目录下的things

Enumeration<URL> dirs;

try {

dirs = Thread.currentThread().getContextClassLoader().getResources(

packageDirName);

// 循环迭代下去

while (dirs.hasMoreElements()) {

// 获取下一个元素

URL url = dirs.nextElement();

// 得到协议的名称

String protocol = url.getProtocol();

// 如果是以文件的形式保存在服务器上

if ("file".equals(protocol)) {

// System.err.println("file类型的扫描");

// 获取包的物理路径

String filePath = URLDecoder.decode(url.getFile(), "UTF-8");

// 以文件的方式扫描整个包下的文件 并添加到集合中

findAndAddClassesInPackageByFile(packageName, filePath,

recursive, classes);

} else if ("jar".equals(protocol)) {

// 如果是jar包文件

// 定义一个JarFile

//  System.err.println("jar类型的扫描");

JarFile jar;

try {

// 获取jar

jar = ((JarURLConnection) url.openConnection())

.getJarFile();

// 从此jar包 得到一个枚举类

Enumeration<JarEntry> entries = jar.entries();

// 同样的进行循环迭代

while (entries.hasMoreElements()) {

// 获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件

JarEntry entry = entries.nextElement();

String name = entry.getName();

// 如果是以/开头的

if (name.charAt(0) == ‘/‘) {

// 获取后面的字符串

name = name.substring(1);

}

// 如果前半部分和定义的包名相同

if (name.startsWith(packageDirName)) {

int idx = name.lastIndexOf(‘/‘);

// 如果以"/"结尾 是一个包

if (idx != -1) {

// 获取包名 把"/"替换成"."

packageName = name.substring(0, idx)

.replace(‘/‘, ‘.‘);

}

// 如果可以迭代下去 并且是一个包

if ((idx != -1) || recursive) {

// 如果是一个.class文件 而且不是目录

if (name.endsWith(".class")

&& !entry.isDirectory()) {

// 去掉后面的".class" 获取真正的类名

String className = name.substring(

packageName.length() + 1, name

.length() - 6);

try {

// 添加到classes

classes.add(Class

.forName(packageName + ‘.‘

+ className));

} catch (ClassNotFoundException e) {

// log

// .error("添加用户自定义视图类错误 找不到此类的.class文件");

e.printStackTrace();

}

}

}

}

}

} catch (IOException e) {

// log.error("在扫描用户定义视图时从jar包获取文件出错");

e.printStackTrace();

}

}

}

} catch (IOException e) {

e.printStackTrace();

}

return classes;

}

/**

* 以文件的形式来获取包下的所有Class

*

* @param packageName

* @param packagePath

* @param recursive

* @param classes

*/

public static void findAndAddClassesInPackageByFile(String packageName,

String packagePath, final boolean recursive, Set<Class<?>> classes) {

// 获取此包的目录 建立一个File

File dir = new File(packagePath);

// 如果不存在或者 也不是目录就直接返回

if (!dir.exists() || !dir.isDirectory()) {

// log.warn("用户定义包名 " + packageName + " 下没有任何文件");

return;

}

// 如果存在 就获取包下的所有文件 包括目录

File[] dirfiles = dir.listFiles(new FileFilter() {

// 自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件)

public boolean accept(File file) {

return (recursive && file.isDirectory())

|| (file.getName().endsWith(".class"));

}

});

// 循环所有文件

for (File file : dirfiles) {

// 如果是目录 则继续扫描

if (file.isDirectory()) {

findAndAddClassesInPackageByFile(packageName + "."

+ file.getName(), file.getAbsolutePath(), recursive,

classes);

} else {

// 如果是java类文件 去掉后面的.class 只留下类名

String className = file.getName().substring(0,

file.getName().length() - 6);

try {

// 添加到集合中去

//classes.add(Class.forName(packageName + ‘.‘ + className));

//经过回复同学的提醒,这里用forName有一些不好,会触发static方法,没有使用classLoader的load干净

classes.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + ‘.‘ + className));

} catch (ClassNotFoundException e) {

// log.error("添加用户自定义视图类错误 找不到此类的.class文件");

e.printStackTrace();

}

}

}

}

}

Bean描述类

public class Bean {

/* Bean Class */

private Class beanClass;

/* Bean Id */

private String id;

/* Bean Property 需要注入的成员变量*/

private Map<String,Class> properties = new HashMap<String,Class>();

public Class getBeanClass() {

return beanClass;

}

public String getId() {

return id;

}

public Map<String, Class> getProperties() {

return properties;

}

public void setBeanClass(Class beanClass) {

this.beanClass = beanClass;

}

public void setId(String id) {

this.id = id;

}

public void setProperties(Map<String, Class> properties) {

this.properties = properties;

}

}

annotation类两个

@Retention(RetentionPolicy.RUNTIME)

public @interface Injection {

}

@Retention(RetentionPolicy.RUNTIME)

public @interface Registration {

String name() default "";  //注册名称

}

模拟实现Spring IOC,布布扣,bubuko.com

时间: 2024-08-22 14:52:59

模拟实现Spring IOC的相关文章

模拟实现Spring IoC功能

为了加深理解Spring 今天自己写了一个模拟的Spring.... 步骤: 1.利用jdom解析bean.xml 2.创建ClassPathXmlApplicaitonContext用于模拟IoC 3.先解析所有的<bean/>,再解析所有的<property/>.如果边解析<bean/>,边解析<property/>,会导致property的ref找不到对应的bean. 4.利用简单的反射实现Ioc. 目录结构: 这里只给出核心代码,其余的bean,da

自己模拟实现spring IOC原理

1.1.IoC是什么 Ioc—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想.在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制.如何理解好Ioc呢?理解好Ioc的关键是要明确“谁控制谁,控制什么,为何是反转(有反转就应该有正转了),哪些方面反转了”,那我们来深入分析一下: ●谁控制谁,控制什么:传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象:而IoC是有专门一个

[Spring系列01]Spring IOC/DI模拟

本文以一个简单的实例大致模拟Spring IOC/DI的运行原理,代码简单分dao,model,service三层.即:dao 与数据库的操作,增删改查等方法model 一般都是javabean对象,例如与数据库的某个表相关联.service 供外部调用,等于对dao,model等进行了包装. 程序结构图如下: 先粘贴部分代码,再进行解释: UserDAO.java package com.ctsh.dao; import com.ctsh.model.User; public interfac

Spring IoC/DI

前言 假设项目层次划分包括logic层和dao层,logic层调用dao层完成业务逻辑,dao层一般与数据库交互.定义两个组件,TestLogic和TestDao,分别操作接口ILogic和IDao,这样程序开发时需要考虑怎样管理这两个组件. 传统方式 这种方式中,当TestLogic组件需要调用TestDao组件时,直接使用关键字new IDao testDao = new TestDao(); 这种方式简单直观,但造成了对外部组件的严重依赖,程序高度耦合,效率低下.当项目需要更换组件时需要修

自己实现简单Spring Ioc

IoC则是一种 软件设计模式,简单来说Spring通过工厂+反射来实现IoC. 原理简单说明: 其实就是通过解析xml文件,通过反射创建出我们所需要的bean,再将这些bean挨个放到集合中,然后对外提供一个getBean()方法,以便我们获得这bean.通俗来讲就如同婚姻介绍所,只需要告诉它找个什么样的女朋友,然后婚介就会按照我们的要求,提供一个mm,如果婚介给我们的人选不符合要求,我们就会抛出异常. 简单实现: 1.需要引用maven依赖: <dependency> <groupId

spring ioc aop 原理

spring ioc aop 原理 spring ioc aop 的原理 spring的IoC容器是spring的核心,spring AOP是spring框架的重要组成部分. 在传统的程序设计中,当调用者需要被调用者的协助时,通常由调用者来创建被调用者的实例.但在spring里创建被调用者的工作不再由调用者来完成,因此控制反转(IoC):创建被调用者实例的工作通常由spring容器来完成,然后注入调用者,因此也被称为依赖注入(DI),依赖注入和控制反转是同一个概念. 面向方面编程(AOP)是以另

介绍 Spring IoC 容器和 bean

简介 本章涵盖了 Spring Framework实现控制翻转 (IoC) 的原则. IoC 有时也被称为依赖注入 (DI).这是一个对象定义他们依赖的过程,其中对象之间的相关性,也就是说,它们一起工作,只能通过构造函数参数,参数工厂方法或设置在其构造后的对象实例或者是从一个工厂方法返回的对象实例的属性上.容器在创建的 bean 注入这些依赖.这个过程是根本的反转,因此称为控制反转(IoC),bean 本身通过直接构造类,或作为 Service Locator(服务定位器)模式的机制,来控制其依

Spring IOC的简单实现(附demo)

简单的说,Spring就是通过工厂+反射将我们的bean放到它的容器中的,当我们想用某个bean的时候,只需要调用getBean("beanID")方法即可. 原理简单说明: Spring容器的原理,其实就是通过解析xml文件,通过反射创建出我们所需要的bean,再将这些bean挨个放到集合中,然后对外提供一个getBean()方法,以便我们获得这bean. 下面我们来简单实现一个demo beans.xml <?xml version="1.0" encod

Spring IoC的概念

大部分的企业架构都基于Spring框架.它的成功来自于理念,而不是技术,它最为核心的理念是IoC(控制反转)和AOP(面向切面编程),其中IoC是Spring的基础,而AOP则是其重要的功能,最为典型的当属数据库事务的使用. Spring的概述 Spring提供了以下策略: •对于POJO的潜力开发,提供轻量级和低侵入的编程,可以通过配置(XML.注解等)来扩展POJO的功能,通过依赖注入的理念去扩展功能,建议通过接口编程,强调OOD的开发模式理念,降低系统耦合度,提高系统可读性和可扩展性. •