要实现的功能:

  1. 将对象的实例化交给自定的ioc容器.
  2. 通过注解的方式对接口进行依赖注入
  3. 通过getBean("userName")方法那到对象,使用对象的方法
  • 首先,创建一个对象,定义对象的构造函数

    • package cn.lisongyu.ioc.demo.bean;
      
      import cn.lisongyu.ioc.annotation.Component;
      
      /**
      * @author lisongyu
      * @ClassName cn.lisongyu.ioc.demo.bean.UserBean
      * @description userbean
      * @create 2018年11月22日 11:08
      */
      @Component //自定义的组件,让ioc容器扫描带有指定注解的类,将当前类装配到ioc容器中
      public class UserBean { @Autowired //自定义的注入注解
      private Service service; public UserBean() {
      System.out.println("UserBean -> instance");
      } public void getUser(){
      service.test(); //接口的方法,如果注入失败,将报空指针异常
      System.out.println("用户详情展示");
      }
      }
    • package cn.lisongyu.ioc.demo.a.b.c;
      
      import cn.lisongyu.ioc.annotation.Component;
      import cn.lisongyu.ioc.demo.a.b.Service; /**
      * @author lisongyu
      * @ClassName cn.lisongyu.ioc.demo.a.b.c.TestService
      * @description Service实现类
      * @create 2018年11月22日 11:22
      */
      @Component
      public class TestService implements Service { public TestService() {
      System.out.println("TestService -> instance");
      } @Override
      public void test() {
      System.out.println("Service 接口实现方法");
      }
      }
    • package cn.lisongyu.ioc.demo.a.b;
      
      /**
      * /**
      *
      * @author lisongyu
      * @ClassName cn.lisongyu.ioc.demo.a.b.Service
      * @description Service接口
      * @create 2018年11月22日 17:31
      */
      public interface Service { void test();
      }
  • 创建自定义的注解

    • package cn.lisongyu.ioc.annotation;
      
      import java.lang.annotation.ElementType;
      import java.lang.annotation.Retention;
      import java.lang.annotation.RetentionPolicy;
      import java.lang.annotation.Target;
      //依赖注入注解
      @Retention(RetentionPolicy.RUNTIME)
      @Target(ElementType.FIELD) //只能注解到字段上
      public @interface Autowired {
      }
    • package cn.lisongyu.ioc.annotation;
      
      import java.lang.annotation.ElementType;
      import java.lang.annotation.Retention;
      import java.lang.annotation.RetentionPolicy;
      import java.lang.annotation.Target;
      //组件注解
      @Retention(RetentionPolicy.RUNTIME) //程序运行时执行
      @Target(ElementType.TYPE) //该注解指定标注的位置 TYPE:类
      public @interface Component {
      }
  • 定义一个接口,用来获取bean对象的方法

    • package cn.lisongyu.ioc.context;
      
      /**
      * /**
      * Application 接口
      * @author lisongyu
      * @ClassName cn.lisongyu.ioc.context.Application
      * @description
      * @create 2018年11月22日 11:24
      */
      public interface Application { Object getBean(String beanName);
      }
    • package cn.lisongyu.ioc.context;
      
      import cn.lisongyu.ioc.annotation.Component;
      
      import java.io.File;
      import java.io.FileFilter;
      import java.net.URL;
      import java.sql.SQLOutput;
      import java.util.ArrayList;
      import java.util.List;
      import java.util.Map;
      import java.util.SortedMap;
      import java.util.concurrent.ConcurrentHashMap; /**
      * @author lisongyu
      * @ClassName cn.lisongyu.ioc.context.ApplicationImpl
      * @description Application的实现类
      * @create 2018年11月22日 11:24
      */
      public class ApplicationImpl implements Application { //定义存放所有类对象的集合
      private List<Class<?>> classList = new ArrayList<>(); //定义存放类的实例对象的集合
      private Map<String,Object> instanceMap = new ConcurrentHashMap<>(); //无参构造
      public ApplicationImpl() {
      } /**
      * 有参构造,通过传入的包路径来实现扫描
      * @param basePackage
      */
      public ApplicationImpl(String basePackage) {
      //扫描包路径
      doScan(basePackage); //实例化
      doIoc(); System.out.println(instanceMap); //依赖注入
      doDi();
      } /**
      * 实例化对象
      */
      private void doIoc() {
      //首先判断一下当前类集合中是否含有元素
      if (classList == null){
      return;
      }
      //遍历集合
      classList.forEach((clz) ->{
      try {
      //通过类对象,实例化一个对象
      Object instance = clz.newInstance();
      //创建key
      String key = getKeyName(clz.getSimpleName());
      //存放到map集合中
      //如果集合中存在则报错
      if (instanceMap.containsKey(key)){
      throw new RuntimeException("相同的类名");
      }
      //放入ioc容器中
      instanceMap.put(key,instance);
      //判断当前类是否实现了接口
      Class<?>[] interfaces = clz.getInterfaces();
      for (Class<?> inter : interfaces) {
      instanceMap.put(inter.getName(),instance);
      }
      } catch (InstantiationException e) {
      e.printStackTrace();
      } catch (IllegalAccessException e) {
      e.printStackTrace();
      }
      });
      } //改名,获取一个首字母小写的类名
      private String getKeyName(String simpleName) {
      char[] chars = simpleName.toCharArray();
      chars[0] += 32;
      return String.valueOf(chars);
      } //依赖注入
      private void doDi() {
      //首先判断实例对象是否有
      if (instanceMap.size() == 0)
      return;
      //遍历所有的实例对象
      instanceMap.forEach((k,v) -> {
      Object instance = v;
      //注入实体对象
      Object injectionInstance = null;
      //通过反射获取类对象
      Class<?> clz = v.getClass();
      //获取当前类对象的所有声明的字段
      Field[] fields = clz.getDeclaredFields();
      //循环遍历所有字段
      for (Field field : fields) {
      //判断字段是否含有@Autowired注解
      if(field.isAnnotationPresent(Autowired.class)){
      String name = field.getType().getName();
      injectionInstance = this.instanceMap.get(name);
      }
      // 通过反射注入到该属性中
      field.setAccessible(true);
      try {
      field.set(instance,injectionInstance);
      } catch (IllegalAccessException e) {
      e.printStackTrace();
      }
      }
      });
      } //包扫描方法
      private void doScan(String basePackage) {
      //获取当前包的位置
      URL resource = this.getClass().getClassLoader().getResource(basePackage.replaceAll("\\.", "/"));
      //创建一个文件对象
      File file = new File(resource.getPath()); //遍历文件
      File[] fileNames = file.listFiles(new FileFilter() {
      @Override
      public boolean accept(File childFile) {
      //判断当前文件是否是一个文件夹
      if (childFile.isDirectory()){ //如果是文件夹,递归,获取所有的class文件
      doScan(basePackage+"."+childFile.getName());
      }else {
      //判断当前文件是否是一个类文件
      if (childFile.getName().endsWith(".class")){
      String classPath = basePackage + "." + childFile.getName().replaceAll("\\.class", "");
      Class<?> clz = null;
      try {
      clz = Class.forName(classPath);
      //判断是否是有@Component注解的类
      if (clz.isAnnotationPresent(Component.class)){
      classList.add(clz);
      }
      } catch (ClassNotFoundException e) {
      e.printStackTrace();
      } }
      }
      return false;
      }
      }); } @Override
      public Object getBean(String beanName) {
      return this.instanceMap.get(beanName);
      }
      }
  • 运行main()

    • package cn.lisongyu.ioc;
      
      import cn.lisongyu.ioc.context.Application;
      import cn.lisongyu.ioc.context.ApplicationImpl;
      import cn.lisongyu.ioc.demo.bean.UserBean; import java.util.*; /**
      * Hello world!
      *
      */
      public class App
      {
      public static void main( String[] args ) { //包路径
      Application app = new ApplicationImpl("cn.lisongyu.ioc.demo"); UserBean userBean = (UserBean) app.getBean("userBean"); userBean.getUser(); } }
  • 结果:

    TestService -> instance		//接口实现类的初始化
    UserBean -> instance //对象类的初始化
    {cn.lisongyu.ioc.demo.a.b.Service=cn.lisongyu.ioc.demo.a.b.c.TestService@4dd8dc3, testService=cn.lisongyu.ioc.demo.a.b.c.TestService@4dd8dc3, userBean=cn.lisongyu.ioc.demo.bean.UserBean@6d03e736} //装配到容器中的类
    Service 接口实现方法 //service.test();
    用户详情展示 //userBean.getUser();

自定义一个IOC框架的更多相关文章

  1. Android Afinal框架学习(二) FinalActivity 一个IOC框架

    框架地址:https://github.com/yangfuhai/afinal 相应的源代码: net.tsz.afinal.annotation.view.* FinalActivity Fina ...

  2. 解读 IoC 框架 InversifyJS

    原文链接 InversityJS 是一个 IoC 框架.IoC(Inversion of Control) 包括依赖注入(Dependency Injection) 和依赖查询(Dependency ...

  3. Android 玩转IOC,Retfotit源码解析,教你徒手实现自定义的Retrofit框架

    CSDN:码小白 原文地址: http://blog.csdn.net/sk719887916/article/details/51957819 前言 Retrofit用法和介绍的文章实在是多的数不清 ...

  4. 【Android开发经验】来,咱们自己写一个Android的IOC框架!

    到眼下位置.afinal开发框架也是用了好几个月了,还记得第一次使用凝视完毕控件的初始化和事件绑定的时候,当时的心情是多么的兴奋- -代码居然能够这样写!然后随着不断的学习,也慢慢的对IOC框架和注解 ...

  5. ASP.NET Core 6框架揭秘实例演示[28]:自定义一个服务器

    作为ASP.NET Core请求处理管道的"龙头"的服务器负责监听和接收请求并最终完成对请求的响应.它将原始的请求上下文描述为相应的特性(Feature),并以此将HttpCont ...

  6. 轻量级IOC框架SwiftSuspenders

    该框架的1.6版本位于https://github.com/tschneidereit/SwiftSuspenders/blob/the-past/,现在已经出了重新架构的2.0版本,所以我决定先研究 ...

  7. 轻量级IOC框架:Ninject (下)

    一,创建依赖链(Chains of Dependency) 当我们向Ninject请求创建一个类型时,Ninject会去检查该类型和其他类型之间的耦合关系.如果有额外的依赖,Ninject也会解析它们 ...

  8. IOC框架Ninject实践总结

    原文地址:http://www.cnblogs.com/jeffwongishandsome/archive/2012/04/15/2450462.html IOC框架Ninject实践总结 一.控制 ...

  9. 国人编写的开源 .net Ioc 框架——My.Ioc 简介

    My.Ioc 是作者开发的一款开源 IoC/DI 框架,下载地址在此处.它具有下面一些特点: 高效 在实现手段上,My.Ioc 通过使用泛型.缓存.动态生成代码.延迟注册.尽量使用抽象类而非接口等方式 ...

随机推荐

  1. CSS3(animation, trasfrom)总结

    CSS3(animation, trasfrom)总结 1. Animation 样式写法: 格式: @-浏览器内核-keyframes 样式名 {} 标准写法(chrome safari不支持 @k ...

  2. Spring容器

    1.Spring简介: a)Spring春天 b)官网:https://spring.io c)设计理念:轮子理念,不要重复创造轮子: d)Spring可以被理解为一个容器,用于管理其他的框架: e) ...

  3. Spark之Yarn提交模式

    一.Client模式 提交命令: ./spark-submit --master yarn --class org.apache.examples.SparkPi ../lib/spark-examp ...

  4. 高端内存映射之kmap持久内核映射--Linux内存管理(二十)

    1 高端内存与内核映射 尽管vmalloc函数族可用于从高端内存域向内核映射页帧(这些在内核空间中通常是无法直接看到的), 但这并不是这些函数的实际用途. 重要的是强调以下事实 : 内核提供了其他函数 ...

  5. Windows Server 2016-查询并导出固定时间段创建AD用户

    生产环境中往往我们有各式各样的需求,例如快速查询某段时间创建用户,或批量导出固定时间段创建用户列表,具体操作如下: $date=Get-Date $oldday=(Get-Date).AddDays( ...

  6. LeetCode算法题-License Key Formatting(Java实现)

    这是悦乐书的第241次更新,第254篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第108题(顺位题号是482).您将获得一个表示为字符串S的许可证密钥,该字符串仅包含字 ...

  7. 线程池工厂方法newScheduledThreadPool(),计划任务

    package com.thread.test.ThreadPool; import java.util.concurrent.Executors; import java.util.concurre ...

  8. RabbitMQ持久化

    我们知道,如果消息接收端挂了,消息会保存在队列里.下次接收端启动就会接收到消息. 如果RabbitMQ挂了怎么办呢?这时候需要将消息持久化到硬盘 消息发送端:producer ........... ...

  9. Tree 树形结构

    一.树的基本概念 (1)树(Tree)的概念:树是一种递归定义的数据结构,是一种重要的非线性数据结构. 树可以是一棵空树,它没有任何的结点:也可以是一棵非空树,至少含有一个结点. (2)根(Root) ...

  10. 清除被占用的8080端口,否则npm run dev无法正常运行

    解决方案一: 1. 打开git-bash2. 输入:netstat -ano查看所有端口信息,如图,找到端口 8080,以及对应的 PID 3.输入:tskill PID 即可杀死进程 解决方案二: ...