一起写框架-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的内容
相关文章推荐
- 一起写框架-Ioc内核容器的实现-对象的调用-方法注入容器的对象(十一)
- 一起写框架-Ioc内核容器的实现-对象的调用-@Bean注解注入容器的对象(十二)
- 一起写框架-Ioc内核容器的实现-基础功能-组件注解支持自定义的对象名(九)
- 一起写框架-Ioc内核容器的实现-基础功能-容器对象名默认首字母小写(八)
- 一起写框架-Ioc内核容器的实现-基础API的定义(三)
- 一起写框架-Ioc内核容器的实现-基础功能-ComponentScan支持组件注解限制(七)
- 一起写框架-Ioc内核容器的实现-基础功能-getBean(五)
- .NET领域最为流行的IOC框架之一Autofac WebAPI2使用Autofac实现IOC属性注入完美解决方案 AutoFac容器初步
- 一起写框架-Ioc内核容器的实现-基础功能-ComponentScan支持多包扫描(六)
- 一起写框架-Ioc内核容器的实现-基础功能-ComponentScan(四)
- ASP.NET Core中使用IOC三部曲(二.采用Autofac来替换IOC容器,并实现属性注入)
- ASP.NET Core中使用IOC三部曲(二.采用Autofac来替换IOC容器,并实现属性注入)
- WebAPI2使用Autofac实现IOC属性注入完美解决方案
- 【Spring】【IOC】【Spring容器注入Bean对象的四种方式】【Spring中注入bean对象的注解】
- tp 框架 利用反射实现对象调用方法
- 简单ioc容器实现,可作为插件框架的核心逻辑,个人文档记录
- 关于微软企业库中依赖注入容器Unity两种生成对象的实现u
- js中json对象不规律key的遍历实现和json对象length属性的调用
- 关于微软企业库中依赖注入容器Unity两种生成对象的实现
- spring(IOC) 对象创建时机、对象作用域scope、对象的初始化方法和销毁方法的调用、spring容器总结