您的位置:首页 > 其它

一起写框架-Ioc内核容器的实现-对象的调用-属性注入容器的对象(十)

2017-11-11 18:44 746 查看

实现功能

需求:在类的成员属性使用@Autowirde注解注入容器中的对象。

实现思路

要实现这个功能。我们首先要思考一个问题:类与类的关系是在调用的建立的,还是说在创建对象的时候就就将建立了?

---我实现的方案是,在在程序启动后,所有对象创建后直接就将对象的属性和属性之间的关系创建了。接下来我就用这个思路来实现,将根据@Autowirde建立对象与对象之间的关系。

为什么一定要对象全部创建后再实现对象与对象直接的关系呢?

这个是逻辑问题,如果对象没有创建完就建立对象与对象之间的关系,人家都还没有创建,你怎么引用呢?对吧。所有一定在所有对象创建完后建立对象与对象的关系。

实现步骤

1.Context接口增加一个方法。用于通过Map的和属性名对象或者对象的类型与属性的类型对象,给属性匹配对象。定义如代码的说明

/**
* 根据类的类型以及设置的对象名返回容器对象
* 如果传入的类型容器中有对应key的对象,而且返回类型是兼容的,直接返回对应的对象。
* 如果传入的类型容器中有没有对应key的对象,那么判断传入的类型是否和容器的对象的找到唯一配置的。
* 如果传入类型唯一匹配,返回对象。如果没有或者配配多个对象,都报一个RuntimeException异常
* @param classType
* @return
*/
Object getObject(Class<?> classType,String key);


2.在ContextImpl容器实现类实现这个方法

@Override
public Object getObject(Class<?> classType, String key) {
// 1.判断是否有对应key的对象
Object object = objects.get(key);
// 2.如果有,而且类型也兼容。直接返回该对象。
if (object != null && classType.isAssignableFrom(object.getClass())) {
return object;
} else {
// 3.如果没有对应key的对象,那么就在容器里检索,是否有兼容类型的对象。
Collection<Object> values = objects.values();
Iterator<Object> iterator = values.iterator();
int count = 0;
Object currentObject = null;
while (iterator.hasNext()) {
Object nextObject = iterator.next();
//判断classType是否是nextObject.getClass()的兼容类型。
boolean from = classType.isAssignableFrom(nextObject.getClass()) ;
if (from) {
//如果发现有对象,计数加1
count++;
//并将对象赋予当前对象
currentObject = nextObject;
}
}
// 如果兼容类型的对象只有一个,返回这个对象。如果大于一个,返回null
if (count == 1) {
return currentObject;
} else {
//如果发现一个类型容器中有多个异常,抛异常
throw new RuntimeException("容器中找不到对应的对象或者找到的对象不是唯一的!请确认是否一个接口继承了多个类");
}

}

}


3.在AbstractApplicationContext容器操作类实现属性的注入方法 autowired()

/**
* 给对象的属性注入关联的对象
* @throws IllegalArgumentException
* @throws IllegalAccessException
*/
private void autowired() throws IllegalArgumentException, IllegalAccessException {
// 1.获得容器
Context context = contexts.get();
// 2.获得容器中的所有对象。
Map<String, Object> objects = context.getObjects();
// 3.获得容器中所有的对象值
Collection<Object> values = objects.values();
// 4.获得对象的迭代器
Iterator<Object> iterator = values.iterator();
while (iterator.hasNext()) {
Object object = iterator.next();
// 5.获得对象的表结构
Class<? extends Object> classType = object.getClass();
// 6.获得字段的结构
Field[] fields = classType.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
// autowired获得注解
Autowired autowired = fields[i].getAnnotation(Autowired.class);
if (autowired != null) {
Class<?> fieldType = fields[i].getType();
String fieldName = fields[i].getName();
// 如果容器里面有对应的对象
Object fieldObject = context.getObject(fieldType, fieldName);
// 允许访问私有方法
if (fieldObject != null) {
// 属性是私有的也可以访问
fields[i].setAccessible(true);
// 将属性值赋予这个对象的属性
fields[i].set(object, fieldObject);
}

}
}
}
}


4. 在AbstractApplicationContext构造方法最后调用属性注入方法autowired,注意标红处

public AbstractApplicationContext(Class<?> classType) {
try {
// 判断配置类是否有Configuration注解
Configuration annotation = classType.getDeclaredAnnotation(Configuration.class);
if (annotation != null) {
// 获得组件扫描注解
ComponentScan componentScan = classType.getDeclaredAnnotation(ComponentScan.class);
// 获得包名
this.basePackage = componentScan.basePackages();
// 根据包名获得类全限制名
// Set<String> classNames =
// PackageUtils.getClassName(this.basePackage[0], true);
// 将扫描一个包,修改为多个包
Set<String> classNames = PackageUtils.getClassNames(this.basePackage, true);
// 通过类名创建对象
Iterator<String> iteratorClassName = classNames.iterator();
while (iteratorClassName.hasNext()) {

String className = iteratorClassName.next();
// System.out.println(className);

// 通过类全名创建对象
Class<?> objectClassType = Class.forName(className);
/*
* 判断如果类权限名对应的不是接口,并且包含有@Component|@Controller|@Service|
*
* @Repository 才可以创建对象
*/
if (this.isComponent(objectClassType)) {
Object instance = objectClassType.newInstance();
// 修改为,默认对象支持首字符小写
String objectName = null;
// 获得组件注解的name属性值
String componentName = this.getComponentOfName(objectClassType);

if (componentName == null) {
// 如果组件注解的name属性没有值,使用默认命名对象
objectName = NamingUtils.firstCharToLower(instance.getClass().getSimpleName());
} else {
// 如果组件注解的name属性有值,使用自定义命名对象
objectName = componentName;
}
this.getContext().addObject(objectName, instance);
}

}
}
48             //1.注入对象到属性中。
49             autowired();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}

}


测试代码

测试类目录结构



1.修改UserController代码,增加注入UserService的代码

package ioc.core.test.controller;

import ioc.core.annotation.Autowired;
import ioc.core.annotation.stereotype.Controller;
import ioc.core.test.service.UserService;

@Controller
public class UserController {

/**
* 通过@Autowired可以注入UserService的对象。
*/
@Autowired
private UserService userServiceImpl;

public void login(){
System.out.println("-登录Controller-");
userServiceImpl.login();
}

}


2.调用UserController 对象

package ioc.core.test;

import org.junit.Test;

import ioc.core.impl.AnntationApplicationContext;
import ioc.core.test.config.Config;
import ioc.core.test.controller.UserController;

public class AnntationApplicationContextTest {

@Test
public void login(){
try {
AnntationApplicationContext context=new AnntationApplicationContext(Config.class);
UserController userController = context.getBean("userController", UserController.class);
userController.login();
System.out.println(context.getContext().getObjects());

} catch (Exception e) {
e.printStackTrace();
}
}

}


3.输出结果

同时输出了UserController的内容和UserService的内容

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐