一起写框架-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对象。说明成功!

时间: 2024-10-30 17:39:53

一起写框架-Ioc内核容器的实现-对象的调用-方法注入容器的对象(十一)的相关文章

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

实现功能 需求:在类的成员属性使用@Autowirde注解注入容器中的对象. 实现思路 要实现这个功能.我们首先要思考一个问题:类与类的关系是在调用的建立的,还是说在创建对象的时候就就将建立了? ---我实现的方案是,在在程序启动后,所有对象创建后直接就将对象的属性和属性之间的关系创建了.接下来我就用这个思路来实现,将根据@Autowirde建立对象与对象之间的关系. 为什么一定要对象全部创建后再实现对象与对象直接的关系呢? 这个是逻辑问题,如果对象没有创建完就建立对象与对象之间的关系,人家都还

一起写框架-Ioc内核容器的实现-对象的调用[email&#160;protected]注解注入容器的对象(十二)

实现功能 现实需求中,有一些类似无法加入扫描组件注解的.如jdk里面的类. 那么框架必须要支持将没有组件注解标识的类也可以有一个方式注入到容器里面. 那么,我们通过类似Spring的@Bean的方案,来实现这个需求. 通过在配置类的方法的上面,使用@Bean注解,将返回的对象加到容器中. 实现思路 获得有@Configuration注解标识的类.检索它的方法,如果有@Bean,执行这个方法并将返回的对象放在容器中. 实现步骤 1.定义一个Bean注解 1 package ioc.core.ann

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

实现功能 --前面实现的代码-- 默认的对象名就类名.不符合Java的命名规范.我们希望默认的对象名首字母小写. 实现思路 创建一个命名规则的帮助类.实现将对大写开头的对象名修改为小写开头. 实现步骤 1.创建一个命名规则帮助类 1 package ioc.core.utils; 2 3 /** 4 * 创建命名规则帮助类 5 * 6 * @author ranger 7 * 8 */ 9 public class NamingUtils { 10 /** 11 * 将类名修改为对象名,首字母小

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

实现功能 以上的代码我们发现.我们都是将@ComponentScan扫描的路径下的所有类都加载到容器中的. 而实际需求,我们并不希望所有的类都创建对象,而是加了组件注解@Controller,@Service,@Repository,@Component的类才创建对象 而不加这些标识的类不需要创建对象. 所谓本章就是实现通过组件注解限制哪些类是可以创建对象的,哪些是不可以的. 实现思路 根据获得的类全限制名,获得它的Class对象.通过Class对象判断类的声明上是否有组件注解.有就创建对象,没

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

实现功能 如果扫描组件注解(@Controller,@Service,@Repository,@Component)默认对象名,已经实现了默认使用首字母小写类名的作为对象名. 但,现实需求中.我们有时候希望可以自己定义对象的名. 实现思路 1.获得扫描组件注解的name属性的值. 2.将这个值作为对象名 实现步骤 1.在AbstractApplicationContext增加一个方法getComponentOfName,用于判断组件注解是否设置了name属性.如果设置了就获得该值 1 /** 2

Spring IOC 容器源码分析 - getBean调用方法解析(三) -- 实例化 Bean 对象

1. createBeanInstance protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) { // 解析 bean ,将 bean 类名解析为 class 引用 Class<?> beanClass = resolveBeanClass(mbd, beanName); /* * 检测类的访问权限.默认情况下,对于非 public

从零开始手写 spring ioc 框架,深入学习 spring 源码

IoC Ioc 是一款 spring ioc 核心功能简化实现版本,便于学习和理解原理. 创作目的 使用 spring 很长时间,对于 spring 使用非常频繁,实际上对于源码一直没有静下心来学习过. 但是 spring 源码存在一个问题,那就是过于抽象,导致学习起来成本上升. 所以本项目由渐入深,只实现 spring 的核心功能,便于自己和他人学习 spring 的核心原理. spring 的核心 Spring 的核心就是 spring-beans,后面的一切 spring-boot,spr

Spring框架—— IOC容器和Bean的配置

 1 IOC和DI ①IOC(Inversion of Control):反转控制. 在应用程序中的组件需要获取资源时,传统的方式是组件主动的从容器中获取所需要的资源,在这样的模式下开发人员往往需要知道在具体容器中特定资源的获取方式,增加了学习成本,同时降低了开发效率. 反转控制的思想完全颠覆了应用程序组件获取资源的传统方式:反转了资源的获取方向--改由容器主动的将资源推送给需要的组件,开发人员不需要知道容器是如何创建资源对象的,只需要提供接收资源的方式即可,极大的降低了学习成本,提高了开发的效

一起写框架-说在前面的话(一)

本人的想法: 互联网中,一堆框架.浮躁的社会,到处都是秒天秒地的广告. 各种Struts,Spring,Hibernate,Mybatis的学习教程充斥互联网.让人有一种错觉,只要学会框架,就可以解决一切问题! 而我,从入行就开始的思考一个问题:作为一个Java程序员,难道仅仅就会几个框架就满足了吗? 有没有想过试试,自己也写一个! 然而:事与人违!充满冲劲的时候,小白一个,什么也不懂.当开始入行后,一直忙碌活地为生存而活着,早已将这个曾经强烈的欲望压到了脑后. 最近,终于开始有了一点点时间,而