我们要完成自动装配,那么就要有一个存放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自动装配。有喜欢的朋友可以参考代码。点击下载