Spring中我们用到的功能实现:基于注解的Ioc自动装配

  我们要完成自动装配,那么就要有一个存放bean对象的容器,然后要有装配的注解,那么哪些类该被存到容器呢,在spring中我们使用过@Service、@Resource等,看下面的代码,你也可以做到。

    来看看这是一个简单的容器接口

/**
 * 容器接口
 * @author:rex
 * @create_time:2014-6-26
 * @version:V1.0
 */
public interface Container {

	Object getBean(String name, BeanType beanType);

	Object getBean(Class<?> type, BeanType beanType);

	Set<?> getBeanNames();

	Collection<?> getBeans();

	boolean hasBean(Class<?> clazz);

	boolean hasBean(String name);

	void registBean(Class<?> clazz);

	void initWired();

}

    这个容器提供了基础的存取方法,分别是获取bean对象和注册、是否包含bean,还有一个初始化的方法。

    接下来我们来为容器做一个基本的实现。    

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import com.biezhi.ioc.BeanType;
import com.biezhi.ioc.Container;
import com.biezhi.ioc.anntation.Autowired;

/**
 * 默认的bean容器实现
 * @author:rex
 * @create_time:2014-6-26
 * @version:V1.0
 */
public class DefaultContainerImpl implements Container {

	//存放bean的容器
	private final Map<String, Object> beansMap = new HashMap<String, Object>();

	public DefaultContainerImpl() {
		//初始化加载bean
		ContainerLoader c = new ContainerLoader(this);
		c.init();
	}

	@Override
	public Object getBean(String name, BeanType beanType) {
		try {
			if(beanType == BeanType.NEW)
				return Class.forName(name).newInstance();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return beansMap.get(name);
	}

	@Override
	public Object getBean(Class<?> type, BeanType beanType) {
		try {
			if(beanType == BeanType.NEW)
				return type.newInstance();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		Iterator<Object> it = this.beansMap.values().iterator();
		while(it.hasNext()){
			Object obj = it.next();
			if(type.isAssignableFrom(obj.getClass())){
				return obj;
			}
		}
		return null;
	}

	@Override
	public Set<?> getBeanNames(){
		return beansMap.keySet();
	}

	@Override
	public Collection<?> getBeans(){
		return beansMap.values();
	}

	@Override
	public boolean hasBean(Class<?> clz) {
		if(null != this.getBean(clz, null)){
			return true;
		}
		return false;
	}

	@Override
	public boolean hasBean(String name){
		if(null != this.getBean(name, null)){
			return true;
		}
		return false;
	}

	/**
	 * 注册一个bean对象到容器里
	 */
	@Override
	public void registBean(Class<?> clazz){
		String name = clazz.getCanonicalName();
		try {
			if(!Modifier.isAbstract(clazz.getModifiers()) && 
			    !Modifier.isInterface(clazz.getModifiers())){
				Object obj = clazz.newInstance();
				beansMap.put(name, obj);
			}
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} 
	}

	/**
	 * 初始化注入
	 */
	@Override
	public void initWired(){
		Iterator<Object> it = this.beansMap.values().iterator();
		try {
			while(it.hasNext()){
				Object obj = it.next();
				Field[] fields = obj.getClass().getDeclaredFields();
				for(Field field : fields){
					Autowired autowired = 
					    field.getAnnotation(Autowired.class);
					if(null != autowired){
						//要注入的字段
						Object wiredField = 
						    this.getBean(field.getType(), null);
						if(null == wiredField){
    						       throw new RuntimeException("Unable to load "+field.getType().getCanonicalName()+"!");
						}
						boolean accessible = field.isAccessible();
						field.setAccessible(true);
						field.set(obj, wiredField);
						field.setAccessible(accessible);
					}
				}
			}
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} 
	}
}

    在构造器里将扫描到的类加载到容器里,然后提供注册bean和获取bean的方法。

import java.io.File;
import java.io.FileFilter;
import java.util.HashSet;
import java.util.Set;

import com.biezhi.ioc.Container;
import com.biezhi.ioc.anntation.Service;
import com.biezhi.ioc.util.ClassHelper;

/**
 * 加载容器bean
 * @author:rex
 * @create_time:2014-6-26
 * @version:V1.0
 */
public class ContainerLoader {

	private Container container;

	public ContainerLoader(Container container) {
		this.container = container;
	}

	public void init(){
		//加载要扫描的包,这里可以使用配置文件,我们就默认扫描所有类
		Set<String> packages = getPackages();
		for(String pack : packages){
			scanPack(pack);
		}
		//初始化注入
		container.initWired();
	}

	private void scanPack(String pack){
		Set<Class<?>> classes = ClassHelper.scanPackage(pack);
		for(Class<?> clazz : classes){
			// 这里我只把带有@Service注解的存进去了,你也可以存其他的或者全部
			Service service = clazz.getAnnotation(Service.class);
			if(null != service){
				//将扫描到的对象保存到容器中
				container.registBean(clazz);
			}
		}
	}

	/**
	 * 获取当前classes的包名称
	 * @author:rex  
	 * @return
	 */
	private Set<String> getPackages(){
		Set<String> packages = new HashSet<String>();
		String appPath = ContainerLoader.class.getResource("/").getPath();
		File classDir = new File(appPath);
		// 如果存在 就获取包下的所有文件 包括目录
		File[] dirfiles = classDir.listFiles(new FileFilter() {
			public boolean accept(File file) {
				return file.isDirectory();
			}
		});
		for(File f : dirfiles){
			packages.add(f.getName());
		}
		return packages;
	}
}

    这个类是加载需要的类文件。还有几个代码文件没有贴出来,想看代码的等会打包自己看。

    接下来我们看看这个测试,

    

@Service
public class A {

	String name = "菊花";

	public void say(){
		System.out.println("hello, I,m rex !");
	}
}
@Service
public class B {

	@Autowired
	private A a;

	private String qq = "3838438";

	public void hehe(){
		a.say();
		System.out.println("请问您是" + a.name + "吗?");
	}

	public String getQq(){
		return this.qq;
	}
}
public class Test {

	public static void main(String[] args) {
		Container c = new DefaultContainerImpl();
		c.initWired();
		//System.out.println(c.getBeanNames());
		B b = (B) c.getBean(B.class, BeanType.SINGLE);
		b.hehe();
		System.out.println(b.getQq());
		System.out.println("==================");
		B b2 = (B) c.getBean(B.class, BeanType.NEW);
		b2.hehe();
	}
}

    运行结果:

hello, I,m rex !
请问您是菊花吗?
3838438
==================
Exception in thread "main" java.lang.NullPointerException
	at com.biezhi.ioc.test.B.hehe(B.java:15)
	at com.biezhi.ioc.test.Test.main(Test.java:18)

好了,这样就基本完成了一个简单的ioc自动装配。有喜欢的朋友可以参考代码。点击下载

时间: 2024-11-16 02:55:47

Spring中我们用到的功能实现:基于注解的Ioc自动装配的相关文章

Spring Batch 2将支持工作划分和基于注解的配置

这一版本的新特性可以分为四类:对Java 5的支持.非顺序执行.增强的可伸缩性以及注解. 对Java 5的支持: Spring Batch 2.0版支持Java 5泛型和参数化类型,以便可以在编译时检查类型安全性.例如,ItemReader接口现在有了一个类型安全的read方法. 非顺序执行: 这其实包括3个新特性--条件.暂停和并行执行.凭借这些特性,各步骤可以按非线性顺序执行.即使工作(Job)中的某个步骤(step)失败,整个工作也依然能够完成.有条件执行(Conditional exec

利用myeclilpse中的hibernate reverse engineering功能无法生成注解

问题描述 求解这是什么原因,我的MyEclipse版本是8.6的,用的hibernate是3.3 解决方案

浅析Spring中的注解

    Spring的配置,通常有两种:使用配置文件和注解.那么Spring如何知道各个Bean或者Service.Controller以及Bean中各类属性之间的关系呢?答案肯定是在定义各个Java文件的时候使用了各种注解,它们交织在一起,实现了使用配置文件完成的配置功能. 一.Bean相关的注解     与SpringBean相关的注解有以下四大类: @Component:标注一个普通的Spring Bean类 @Controller:标注一个控制器组件类 @Service:标注一个业务逻辑

Facebook在其iPhone版应用中新增了一个tips功能

摘要: 近日Facebook在其iPhone版应用中新增了一个tips功能,基于用户的实时位置,显示一系列关于这个地点的卡片信息.另外,如果你的朋友曾经在这儿分享过图片或帖子的话,也会显示出来. 近日Facebook在其iPhone版应用中新增了一个"tips"功能,基于用户的实时位置,显示一系列关于这个地点的卡片信息.另外,如果你的朋友曾经在这儿分享过图片或帖子的话,也会显示出来.早在两年前Facebook曾经推出类似的Nearby功能,但是在之后一段时间内似乎都没有威胁到Yelp和

spring中DispatcherServlet的运行机制

servlet Spring中DispatcherServlet的运行机制 DispatcherServlet是spring的web框架(以下简称SpringWeb)中的核心servlet."Spring的web框架--象其它web框架一样--是一个请求驱动的web框架,其设计围绕一个能将请求分发到控制器的servlet,它也提供其它功能帮助web应用开发."----<Spring Framework 开发参考手册(中文版)>而在SpringWeb框架中这个servlet就

Spring中的四种声明式事务的配置

Spring中的四种声明式事务的配置Spring容器中有两种思想很重要,也就是我们常用的Ioc和Aop,如果理解了这两种思想,对于我们学习设计模式和编程有很大的帮助,美国四人帮(GOF)写的设计模式中,有很多都用到了Ioc的思想.简单的说就是依赖注入的思想.常见的一种情况:如果一个类中要复用另外一个类中的功能时,我们可能会首先想到继承,如果你知道Ioc这种思想的话,我想你不会用继承,你会马上想到把要用到功能抽取出来,在我们要用到的类中只需通过set方法简单的注入就可以了,其实这里用到了对象的组合

在SPRING中实现事务暂停的方法

摘要 Spring框架是一个流行的基于轻量级控制反转容器的Java/J2EE应用框架,尤其在数据访问和事务管理方面的能力是众所周知的.Spring的声明性事务分离可以应用到任何POJO目标对象,并且包含所有EJB基于容器管理事务中的已声明事务.后台的事务管理器支持简单的基于JDBC的事务和全功能的基于JTA的J2EE事务. 这篇文章详细的讨论了Spring的事务管理特性.重点是如何在使用JTA作为后台事务策略的基础上让POJO利用Spring的声明性事务,这也显示了Spring的事务服务可以无缝

Spring中的Template和Callback模式

Spring中的Callback模式与Template模式合用,随处可见.Template method被广泛的使用,像Servlet就是使用这个模式.Template mothod模式虽然能简化很多重复的代码,但这种模式的也有不少限制.Template mothod将一个功能的实现分成许多小的步骤,在父类中定义了这些步骤的顺序,让子类来具体实现每一个小的步骤.这些小的步骤是protected,以防止用户不正确的使用这些小的步骤而产生异常.这样就产生了一个限制,那就是你需要继承Template然

Spring 2.5的新特性:配置简化和基于注解的功能

简介 从诞生之初,Spring框架就坚守它的宗旨:简化企业级应用开发,同时给复杂问题提供强大的.非侵入性解决方案.一年前发布的Spring 2.0就把这些主题推到了一个新的高度.XML Schema的支持和自定义命名空间的使用大大减少了基于XML的配置.使用Java 5及更新版本java的开发人员如今可以利用植入了像泛型(generic)和注解等新语言特性的Spring库.最近,和AspectJ表达式语言的紧密集成,使得以非侵入方式添加跨越定义良好的Spring管理对象分组的行为成为可能. 新发