您的位置:首页 > 编程语言 > Java开发

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

2014-06-26 15:54 926 查看
我们要完成自动装配,那么就要有一个存放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自动装配。有喜欢的朋友可以参考代码。点击下载
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  spring ioc