一起写框架-Ioc内核容器的实现-对象的调用-方法注入容器的对象

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一起写框架-Ioc内核容器的实现-对象的调用-方法注入容器的对象相关的知识,希望对你有一定的参考价值。

实现功能

就是在方法的上面加入@Autowired注解,容器中的对象会注入到对应类型的参数。

注意:暂时实现注入一个对象。所有方法的参数列表的参数只能有一个。

实现思路

其实实现的思路和给字段注入的逻辑是一样的。遍历类所有的方法有没有@Autowired,有的就给它赋予容器中对应的对象。

 

实现步骤

1. 在AbstractApplicationContext增加两个方法区分属性注入(autowiredField)和方法注入(autowiredMethod

 

 1 /**
 2      * 属性注入
 3      * @param object
 4      * @param context
 5      * @throws IllegalArgumentException
 6      * @throws IllegalAccessException
 7      */
 8     private void autowiredField(Object object,Context context) throws IllegalArgumentException, IllegalAccessException {
 9         // 5.获得对象的表结构
10         Class<? extends Object> classType = object.getClass();
11         // 6.获得字段的结构
12         Field[] fields = classType.getDeclaredFields();
13         for (int i = 0; i < fields.length; i++) {
14             // autowired获得注解
15             Autowired autowired = fields[i].getAnnotation(Autowired.class);
16             if (autowired != null) {
17                 Class<?> fieldType = fields[i].getType();
18                 String fieldName = fields[i].getName();
19                 // 如果容器里面有对应的对象
20                 Object fieldObject = context.getObject(fieldType, fieldName);
21                 // 允许访问私有方法
22                 if (fieldObject != null) {
23                     // 属性是私有的也可以访问
24                     fields[i].setAccessible(true);
25                     // 将属性值赋予这个对象的属性
26                     fields[i].set(object, fieldObject);
27                 }
28 
29             }
30         }
31     }
32     /**
33      * 注意set方法的规范
34      * 限定方法只能注入一个参数,并且注入对象的方法只能有一个参数
35      * @param object
36      * @param context
37      * @throws IllegalArgumentException
38      * @throws IllegalAccessException
39      * @throws InvocationTargetException
40      */
41     private void autowiredMethod(Object object,Context context) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
42         // 5.获得对象的表结构
43         Class<? extends Object> classType = object.getClass();
44         // 6.获得类方法的结构
45         Method[] methods = classType.getDeclaredMethods();
46         for (int i = 0; i < methods.length; i++) {
47             // autowired获得注解
48             Autowired autowired = methods[i].getAnnotation(Autowired.class);
49             if (autowired != null) {
50                 //获得参数列表的类型
51                 Class<?>[] parameterTypes = methods[i].getParameterTypes();
52                 
53                 String fieldName = methods[i].getName();
54                 
55                 // 如果容器里面有对应的对象,限定一个方法只能注入一个对象
56                 Object methodObject = context.getObject(parameterTypes[0], fieldName);
57                 // 允许访问私有方法
58                 if (methodObject != null) {
59                     // 属性是私有的也可以访问
60                     methods[i].setAccessible(true);
61                     // 将属性值赋予这个对象的属性
62                     methods[i].invoke(object, methodObject);
63                 }
64 
65             }
66         }
67     }

 

2.修改autowired方法的逻辑。将原来只遍历属性的@Autowired注解,修改为同时遍历属性和方法上面的的对象注入注解@Autowired

    /**
     * 给对象的属性注入关联的对象
     * @throws IllegalArgumentException
     * @throws IllegalAccessException
     * @throws InvocationTargetException 
     */
    private void autowired() throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
        // 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();
           //1.注入到属性
            this.autowiredField(object, context);
            //2.注入到方法
            this.autowiredMethod(object, context);
        }
    }

测试代码

测试目录结构

技术分享

1.在UserServiceImpl类里面增加通过方法注入UserDAO的注解

 1 package ioc.core.test.service.impl;
 2 
 3 import ioc.core.annotation.Autowired;
 4 import ioc.core.annotation.stereotype.Service;
 5 import ioc.core.test.dao.UserDAO;
 6 import ioc.core.test.service.UserService;
 7 
 8 /**
 9  * 一个普通的类,用于测试是否可以创建对象
10  * @author ranger
11  *
12  */
13 @Service
14 public class UserServiceImpl implements UserService {
15     
16     @Autowired
17     private UserDAO userDAO;
18     
19     @Override
20     public void login(){
21         System.out.println("-登录Service-");
22         userDAO.save();
23     }
24 
25 }

2.测试类调用UserController的对象

 1 package ioc.core.test;
 2 
 3 import org.junit.Test;
 4 
 5 import ioc.core.impl.AnntationApplicationContext;
 6 import ioc.core.test.config.Config;
 7 import ioc.core.test.controller.UserController;
 8 
 9 public class AnntationApplicationContextTest {
10     
11     @Test
12     public void login(){
13         try {
14             AnntationApplicationContext context=new AnntationApplicationContext(Config.class);
15              UserController userController = context.getBean("userController", UserController.class);
16              userController.login();
17             System.out.println(context.getContext().getObjects());
18         
19         } catch (Exception e) {
20             e.printStackTrace();
21         }
22     }
23 
24 }

3.测试结果,同时可以调用UserController,UserServiceImpl,UserDAO对象。说明成功!

技术分享

 

以上是关于一起写框架-Ioc内核容器的实现-对象的调用-方法注入容器的对象的主要内容,如果未能解决你的问题,请参考以下文章

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

一起写框架-Ioc内核容器的实现-基础功能-组件注解支持自定义的对象名

一起写框架-Ioc内核容器的实现-基础功能-容器对象名默认首字母小写

一起写框架-Ioc内核容器的实现-基础功能-ComponentScan支持组件注解限制

一起写框架-控制反转(Ioc)概述

Spring的IOC分析源码