这是个很简单的IOC容器,基本功能有:自动加载所有使用了@Inject注解的类,然后注入每个类里边使用了@Inject注解的字段。
原理很简单,就是扫描classes目录下的所有文件和子目录文件,如果是.class文件就检查是否有@Inject这个注解,有就加载,然后在分析这个类,看字段有没有使用了@Inject这个注解的,有就尝试注入(注入是在所有类加载完之后进行的)。
首先,是一个接口:Container.java,定义了容器的一些方法。
代码如下:
package com.easyjf.minicontainer;
import java.util.Collection; import java.util.List;
import java.util.Map;
public interface Container {
void init();
Object getBean(String name);
Object getBean(Class type);
List getBeans(String name);
List getBeans(Class type);
Collection getBeanName();
boolean hasBean(Class clz);
boolean hasBean(String name);
void registBean(Class clz);
}
这里定义的是容器的通用方法,比如从容器获取一个bean,向容器中注册一个bean等。
接下来是容器类的实现,这个容器很简单,代码集中在初始化过程,初始化的时候会加载类,并注入某些字段。
package com.easyjf.minicontainer.impl;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import com.easyjf.minicontainer.Container;
import com.easyjf.minicontainer.annotation.Inject;
public class DefaultContainer implements Container {
private static final Logger logger = Logger.getLogger(DefaultContainer.class);
private final Map objMap = new HashMap();
public Object getBean(String name) {
return objMap.get(name);
}
public Object getBean(Class type) {
Iterator it = this.objMap.values().iterator();
while(it.hasNext()){
Object obj = it.next();
if(type.isAssignableFrom(obj.getClass())){
return obj;
}
}
return null;
}
public Collection getBeanName() {
return null;
}
public List getBeans(String name) {
return null;
}
public List getBeans(Class type) {
return null;
}
public boolean hasBean(Class clz) {
if(this.getBean(clz)!=null){
return true;
}
return false;
}
public boolean hasBean(String name){
if(this.getBean(name)!=null){
return true;
}
return false;
}
public void init() {
Config config = new Config();
config.init(this);
refresh();
}
public void registBean(Class clz){
String name = clz.getCanonicalName();
try {
if(!Modifier.isAbstract(clz.getModifiers())&&!Modifier.isInterface(clz.getModifiers())){
logger.debug("加载了类:"+name);
Object obj = clz.newInstance();
objMap.put(name, obj);
}else{
Inject inject = (Inject)clz.getAnnotation(Inject.class);
String taget = inject.target();
if("".equals(taget)){
throw new RuntimeException(
"接口必须指定目标类!");
}
Class tagetClz = Class.forName(taget);
Object tagetObj = tagetClz.newInstance();
logger.debug("加载了类:"+name);
objMap.put(name, tagetObj);
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public void refresh(){
Iterator it = this.objMap.values().iterator();
while(it.hasNext()){
try {
Object obj = it.next();
String name = obj.getClass().getCanonicalName();
Field[] fields = obj.getClass().getDeclaredFields();
for(Field field : fields){
Annotation inject = field.getAnnotation(Inject.class);
if(inject!=null){
Object arg = this.getBean(field.getType());
if(arg==null){
throw new RuntimeException(
"无法加载"+field.getType().getCanonicalName()+"!");
}
String fieldName = field.getName();
String methodName = "set"
+fieldName.substring(0, 1).toUpperCase()
+fieldName.substring(1, fieldName.length());
Method method;
method = obj.getClass()
.getDeclaredMethod(methodName, arg.getClass());
if(method != null){
method.invoke(obj, arg);
}else{
throw new RuntimeException("无法加载"
+obj.getClass().getCanonicalName()
+"."+field.getName()
+",找不到该字段的set方法!");
}
}
}
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
这里主要说说registBean(Class clz)和refresh()这两个方法。registBean(Class clz)是由另外一个类来调用的,这里主要说说这个方法的功能。这个方法接受一个Class类型的参数,然后判断这个Class是不是接口或者抽象类,如果是就根据其@Inject注解中的target值来找到一个类,并初始化这个类。如果不是就直接实例化并且放入容器中。
refresh()方法则是在加载完需要加载的类之后开始执行注入操作。通过迭代容器中的所有bean,来扫描每一个bean,看看是否有需要注入的字段(即使用了@Inject注解的字段),然后执行这个字段的setter方法,实现注入(未实现构造子注入)。
接下来是Config类,这个类的功能主要是扫面classes目录下的文件,找到所有class文件并尝试交给DefaultContainer来加载。
代码如下:
package com.easyjf.minicontainer.impl;
import java.io.File;
import java.lang.annotation.Annotation;
import java.util.Map;
import org.apache.log4j.Logger;
import com.easyjf.minicontainer.Container;
import com.easyjf.minicontainer.annotation.Inject;
public class Config {
private static final Logger logger = Logger.getLogger(Config.class);
private String packagePath;
private Container container;
public void init(Container container){
this.container = container;
loadClass();
}
public void loadClass(){
loadClassFromDir(getPackagePath());
}
public void loadClassFromFile(String path){
logger.debug("加载类:"+path);
logger.debug(path.endsWith(".class"));
if(path.endsWith(".class")){
String className = path.replace(packagePath, "");
className = className.replace("/", ".");
className = className.substring(1, className.length());
className = className.substring(0, className.indexOf(".class"));
logger.debug(className);
try {
Class clz = Class.forName(className);
Annotation inject = clz.getAnnotation(Inject.class);
if(inject!=null){
container.registBean(clz);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
public void loadClassFromDir(String path){
logger.debug("从文件夹"+path+"加载类");
File file = new File(path);
logger.debug("找到目录:"+path);
if(file.isDirectory()){
String[] paths = file.list();
for(String filePath : paths){
logger.debug("找到子目录:"+filePath);
loadClassFromDir(path+"/"+filePath);
}
}else{
loadClassFromFile(path);
}
}
public String getPackagePath(){
String appPath = Config.class.getResource("/").getPath();
appPath = appPath.substring(1, appPath.length()-1);
logger.debug("包路径:"+appPath);
if(appPath.contains("%20")){
appPath = appPath.replaceAll("%20", " ");
}
this.packagePath = appPath;
return appPath;
}
}
这个类有三个重要方法:getPackagePath()、loadClassFromDir(String path)、loadClassFromFile(String path)。
getPackagePath()功能是获取当前应用的classes目录所处的绝对路径。loadClassFromDir(String path)方法是从一个目录中加载类,这里有一个递归调用,从而遍历所有子目录。loadClassFromFile(String path)的功能就是从一个文件中加载类。
三个类,实现一个简单的IOC,相信大家都能看懂,其实IOC也就那么回事,我们都能写,哈哈!
代码很少,也写得比较粗糙,问题也很多,见笑了!
完整代码请下载,里边还包含了一个测试实例。
地址:http://www.java3z.com/cwbwebhome/article/article5/5880.html?id=1737
分享到:
相关推荐
**IOC容器简单实现** IOC(Inversion of Control)容器是软件设计模式中的一种,它将对象的创建和管理权从代码本身转移到一个外部容器,即IOC容器。这种反转控制使得程序更加灵活,降低了组件之间的耦合性,提高了...
本文将深入探讨一个简单的IOC容器实现,帮助我们理解DI的基本原理。 首先,理解IOC的概念至关重要。在传统的编程模式中,对象通常自行创建依赖的对象,这导致了代码之间的紧密耦合。而在IOC模式下,容器负责管理...
【标题】:“简单IOC容器demo”是一个演示性的项目,它旨在教授如何构建一个基础的控制反转(IOC)容器。这个容器使用注解来实现依赖注入,这是Spring框架的核心特性之一。 【描述】:该示例项目是学习过程的产物,...
Spring IoC容器是Spring框架的核心,它...无论是简单的应用还是复杂的分布式系统,Spring IoC容器都能有效地支撑其运行。随着Spring版本的演进,虽然具体实现可能有所变化,但其核心设计思想和组件架构依然保持稳定。
1. 利用注解、反射和工厂模式设计一个简单的IoC容器 2. 该IoC容器包含3个注解和一个IoC容器类(AnnotationConfigApplicationContext),其定义如下: 注解 含义 @Component 标注Bean @Autowired 标注需要被注入的...
### Spring IoC容器部署实现详解 #### 一、Spring IoC容器概述 Spring框架的核心特性之一就是Inversion of Control(IoC),也被称为Dependency Injection(DI)。IoC容器是Spring框架的重要组成部分,它负责管理...
在Java领域,Spring框架的IOC容器是最为广泛应用的实现之一。当我们自己动手实现IOC容器时,可以更深入地理解其内部的工作机制。 ### 1. IOC基本原理 **控制反转**的核心思想是将对象的创建和管理权交给容器,而...
现在我们来详细探讨一下如何从零开始,用纯Java实现一个简单的IoC容器。 首先,我们要理解IoC的概念。IoC是指将控制权从应用程序的代码中转移出来,交由一个外部容器进行管理。在传统的编程模式中,对象会自行创建...
描述中提到的"手动实现一个IOC容器"意味着我们将探讨如何从基本概念出发,逐步构建一个简单的DI容器。这个过程通常包括以下几个步骤: 1. **定义Bean**: 首先,我们需要定义一个Bean类,它代表了我们需要管理的对象...
在 Java 社区中,有一些流行的 IoC 容器实现了依赖注入,比如 Spring Framework 和 PicoContainer。这些框架提供了一系列工具和 API 来支持 IoC 和 DI,使开发者能够更加高效地组织和管理项目中的组件。 - **Spring...
在实现自定义的Spring IOC容器时,我们需要关注以下几个核心知识点: 1. **Bean的定义与注册**:首先,我们需要创建一个表示Bean的类或接口,包含Bean的ID、类名等信息。Bean的定义可以通过XML配置文件、注解或者...
在`iocDemo`这个例子中,我们可能会看到如何用代码实现一个简单的IOC容器。这通常包括以下步骤: 1. **解析配置**:读取XML配置文件,解析出bean的定义。 2. **创建bean**:根据bean定义创建相应的对象,可以使用...
我们从一个简单的容器开始,一步步的重构,最后实现一个基本的Spring框架的雏形,为了帮助我们更加深入的理解Spring的IoC的原理...【SSH进阶之路】一步步重构容器实现Spring的IoC——工厂+反射+配置文件实现IoC容器(十)
实现一个简单的IOC容器,我们可以从以下几个步骤入手: 1. **Bean定义**:首先需要一种方式来定义Bean,这可以通过类名、属性和依赖关系来描述。可以使用一个HashMap存储这些信息,键为Bean的ID,值为Bean的定义...
通过阅读这篇文章,你可能会了解到如何设计和实现一个简单的IoC容器,以及如何处理各种挑战,如处理循环依赖、性能优化等。 标签“源码”表明文章可能深入到代码层面,讲解如何通过编程实现IoC容器的核心功能。而...
在本项目中,我们通过“利用反射自实现IOC容器”来探讨如何构建一个简单的DI框架,以理解其核心概念和工作原理。 首先,我们需要了解什么是DOM4J。DOM4J是一个Java库,用于处理XML文档,它提供了丰富的API,可以...
接下来,我们讨论Unity作为IOC容器如何实现依赖注入。Unity提供了多种配置方式,包括代码配置、XML配置文件以及通过Attribute标记等。以下是一个简单的Unity配置示例: ```csharp var container = new ...
在`YQIoc`这个压缩包中,可能包含了实现简单模拟Spring IoC容器的代码。通常,这个模拟会包含以下几个部分: 1. **Bean定义**:这是描述对象如何创建和配置的数据结构。在我们的例子中,bean定义可能是以XML形式...
在这个简易版的Java IOC容器实现中,我们将探讨如何通过自定义注解和反射机制来构建一个基础的IoC容器。 首先,我们有两个自定义注解:`@MyComponent` 和 `@MyAutowired`。 1. `@MyComponent` 是一个类型注解,...
在 "MySpring" 这个实现中,你可能已经包含了创建 IoC 容器、解析配置(可能是 XML 或注解)、实例化和管理 Bean 的代码。这将涉及反射机制、Java 注解处理和可能的自定义加载逻辑。通过这个项目,你可以深入理解 ...