ReflectUtils.java (反射工具类)
package top.icss.ioc;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile; /**
* @author cd
* @desc 反射工具类
* @create 2020/3/26 11:30
* @since 1.0.0
*/
public class ReflectUtils { /**
* 是否循环迭代
*/
private final static boolean recursive = true; /**
* 扫描 包下面所有Class
* @param packageName 包名称
* @param <T>
* @return
*/
public static <T> List<Class<T>> getClass(String packageName){
List<Class<T>> list = new ArrayList<>(); String packageNamePath = packageName;
packageNamePath = packageNamePath.replace(".", "/"); Enumeration<URL> resources;
try {
//定义一个枚举的集合 并进行循环来处理这个目录下的things
resources = Thread.currentThread().getContextClassLoader().getResources(packageNamePath);
//循环迭代
while (resources.hasMoreElements()){
URL url = resources.nextElement();
//得到协议的名称
String protocol = url.getProtocol();
//如果是以文件的形式保存在服务器上
if("file".equals(protocol)){
System.err.println("file类型的扫描");
String filePath = URLDecoder.decode(url.getFile(), "utf-8");
// 获取此包的目录 建立一个File
File dir = new File(filePath);
list.addAll(getClass(dir, packageName));
}
} } catch (IOException e) {
e.printStackTrace();
} return list;
} /**
* 迭代查找文件类
* @param filePath
* @param packageName
* @param <T>
* @return
*/
private static <T> List<Class<T>> getClass(File filePath, String packageName){
List<Class<T>> classes = new ArrayList<>();
if(!filePath.exists()){
return classes;
} // 如果存在 就获取包下的所有文件 包括目录
File[] files = filePath.listFiles(new FileFilter() {
//自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件)
@Override
public boolean accept(File file) {
return (recursive && file.isDirectory())
|| file.getName().endsWith(".class");
}
}); for (File file : files){
// 如果是目录 则继续扫描
if(file.isDirectory()){
classes.addAll(getClass(file, packageName + "." + file.getName()));
}else {
// 如果是java类文件 去掉后面的.class 只留下类名
String fileName = file.getName();
String className = fileName.substring(0, fileName.length() - 6);
className = packageName + "." + className;
try {
//这里用forName有一些不好,会触发static方法,没有使用classLoader的load干净
//Class<T> cls = (Class<T>) Class.forName(className);
Class<T> cls = (Class<T>) Thread.currentThread().getContextClassLoader().loadClass(className);
classes.add(cls);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} } return classes;
}
public static void main(String[] args) {
getClass("top.icss");
}
}
MyService.java MyAutowired.java (注解类)
package top.icss.ioc.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; /**
* @author cd
* @desc
* @create 2020/3/26 14:57
* @since 1.0.0
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyService { String value() default "";
}
package top.icss.ioc.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; /**
* @author cd
* @desc 自动注入
* @create 2020/3/26 14:59
* @since 1.0.0
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface MyAutowired { String value() default "";
}
IocContainer.java (IOC容器)
package top.icss.ioc;

import top.icss.ioc.annotation.MyAutowired;
import top.icss.ioc.annotation.MyService; import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; /**
* @author cd
* @desc ioc容器
* @create 2020/3/26 14:48
* @since 1.0.0
*/
public class IocContainer { private Set<Class<?>> clss = new LinkedHashSet<Class<?>>();
private Map<String, Object> beans = new ConcurrentHashMap<String, Object>(); /**
* 获取类上 @MyService的注解类
*
* @param packageName
*/
public void doScanner(String packageName) {
List<Class<Object>> list = ReflectUtils.getClass(packageName);
for (Class cls : list) {
boolean service = cls.isAnnotationPresent(MyService.class);
if (service) {
clss.add(cls);
}
}
} /**
* 将class中的类实例化,经key-value:类名(小写)-类对象放入ioc字段中
*/
public void doInstance() {
for (Class cls : clss) {
if (cls.isAnnotationPresent(MyService.class)) {
MyService myService = (MyService) cls.getAnnotation(MyService.class);
String beanName = "";
if(cls.isInterface()){
beanName = cls.getName();
}else {
beanName = ("".equals(myService.value().trim())) ? toLowerFirstWord(cls.getSimpleName()) : myService.value();
}
try { Object instance = cls.newInstance();
beans.put(beanName, instance); Class[] interfaces = cls.getInterfaces();
for (Class<?> i:interfaces){
beans.put(i.getName(), instance);
} } catch (Exception e) {
e.printStackTrace();
} }
}
} /**
* 自动化的依赖注入
*/
public void doAutowired(){
if(beans.isEmpty()){
return;
} try {
Set<Map.Entry<String, Object>> entries = beans.entrySet();
for (Map.Entry<String, Object> entry: entries){
Class<?> cls = entry.getValue().getClass(); Field[] fields = cls.getDeclaredFields();
//强制获取私有字段
AccessibleObject.setAccessible(fields,true);
for (Field f: fields){
if(!f.isAnnotationPresent(MyAutowired.class)){
continue;
} MyAutowired myAutowired = f.getAnnotation(MyAutowired.class);
String beanName = "";
Class icls = f.getType();
if(icls.isInterface()){
beanName = icls.getName();
}else {
beanName = ("".equals(myAutowired.value().trim())) ? toLowerFirstWord(icls.getName()) : myAutowired.value();
}
//获取当前类实例
Object obj = entry.getValue();
//容器中获取字段实例
Object value = beans.get(beanName); f.set(obj, value); }
}
} catch (Exception e) {
e.printStackTrace();
}
} /**
* 获取实例
* @param cls
* @param <T>
* @return
*/
public <T> T getBean(Class<?> cls){
MyService myService = cls.getAnnotation(MyService.class);
String beanName = "";
if(cls.isInterface()){
beanName = cls.getName();
}else {
beanName = ("".equals(myService.value().trim())) ? toLowerFirstWord(cls.getSimpleName()) : myService.value();
} return (T) beans.get(beanName);
} /**
* 将字符串首字母转换为小写
* @param name
* @return
*/
private String toLowerFirstWord(String name) {
char[] charArray = name.toCharArray();
charArray[0] += 32;
return String.valueOf(charArray);
}
}

测试

Service1.java Service2.java (接口类)
public interface Service1 {

    public void print1();
} public interface Service2 {
public void print2();
}
Service1Impl.java Service2Impl.java (实现类)
package top.icss.ioc.test.impl;

import top.icss.ioc.annotation.MyAutowired;
import top.icss.ioc.annotation.MyService;
import top.icss.ioc.test.Service1;
import top.icss.ioc.test.Service2; /**
* @author cd
* @desc
* @create 2020/3/26 15:45
* @since 1.0.0
*/
@MyService
public class Service1Impl implements Service1 { @MyAutowired
private Service2 service2; @Override
public void print1() {
service2.print2();
}
}
package top.icss.ioc.test.impl;

import top.icss.ioc.annotation.MyAutowired;
import top.icss.ioc.annotation.MyService;
import top.icss.ioc.test.Service1;
import top.icss.ioc.test.Service2; /**
* @author cd
* @desc
* @create 2020/3/26 15:45
* @since 1.0.0
*/
@MyService
public class Service2Impl implements Service2 { @MyAutowired
private Service1 service1; @Override
public void print2() {
System.out.println("print2");
}
}
IocTest.java (测试类)
public class IocTest {

    public static void main(String[] args) throws InterruptedException {
IocContainer ioc = new IocContainer();
ioc.doScanner("top.icss.ioc.test");
ioc.doInstance();
ioc.doAutowired(); Service2 bean = ioc.getBean(Service2Impl.class);
bean.print2(); }
}

手写简单IOC的更多相关文章

  1. Spring源码分析 手写简单IOC容器

    Spring的两大特性就是IOC和AOP. IOC Container,控制反转容器,通过读取配置文件或注解,将对象封装成Bean存入IOC容器待用,程序需要时再从容器中取,实现控制权由程序员向程序的 ...

  2. 利用递归,反射,注解等,手写Spring Ioc和Di 底层(分分钟喷倒面试官)了解一下

    再我们现在项目中Spring框架是目前各大公司必不可少的技术,而大家都知道去怎么使用Spring ,但是有很多人都不知道SpringIoc底层是如何工作的,而一个开发人员知道他的源码,底层工作原理,对 ...

  3. 我自横刀向天笑,手写Spring IOC容器,快来Look Look!

    目录 IOC分析 IOC是什么 IOC能够带来什么好处 IOC容器是做什么工作的 IOC容器是否是工厂模式的实例 IOC设计实现 设计IOC需要什么 定义接口 一:Bean工厂接口 二:Bean定义的 ...

  4. 不使用Tomcat,手写简单的web服务

    背景: 公司使用的YDB提供了http的查询数据库服务,直接通过url传入sql语句查询数据-_-||.ydb的使用参照:https://www.cnblogs.com/hd-zg/p/7115112 ...

  5. 手写一个IOC容器

    链接:https://pan.baidu.com/s/1MhKJYamBY1ejjjhz3BKoWQ 提取码:e8on 明白什么是IOC容器: IOC(Inversion of Control,控制反 ...

  6. 手写简单call,apply,bind

    分析一下call的使用方法:call是显示绑定this指向,然后第一个参数是你所指向的this对象,后面跟着多个参数,以逗号隔开 function sum(num1,num2){ return num ...

  7. 手写简单的jq雪花飘落

    闲来无事,准备写个雪花飘落的效果,没有写太牛逼的特效,极大的简化了代码量,这样容易读取代码,用起来也很简单,对于那些小白简直是福利啊,简单易读易学.先直接上代码吧,然后再一一讲解,直接复制粘贴就可以拿 ...

  8. 利用Java手写简单的httpserver

    前言: 在看完尚学堂JAVA300中讲解如何实现一个最简单的httpserver部分的视频之后, 一.前置知识 1.HTTP协议 当前互联网网页访问主要采用了B/S的模式,既一个浏览器,一个服务器,浏 ...

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

    IoC Ioc 是一款 spring ioc 核心功能简化实现版本,便于学习和理解原理. 创作目的 使用 spring 很长时间,对于 spring 使用非常频繁,实际上对于源码一直没有静下心来学习过 ...

随机推荐

  1. js 网页运行原理

    当我们打开一个网页的时候,浏览器会首先创建一个窗口,这个窗口就是我所知道的window对象,也就是整个Javascript运行所依附的全局变量. 为了加载网页文档,当前窗口又需要创建一个Documen ...

  2. Ionic3学习笔记(七)Storage

    本文为原创文章,转载请标明出处 目录 简介 安装 配置 使用 1. 简介 Storage可以很容易的存储键值对和JSON对象.Storage在底层使用多种存储引擎,根据运行平台选择最佳的存储方式. 当 ...

  3. Rails (栈)

    题目链接:https://vjudge.net/problem/UVA-514 题目大意: 有A,B,C三个火车停靠点,火车最初停在A站,给你一个序列,问你能不能通过中转站C到达B站,火车从A站进入到 ...

  4. 3名程序员被抓!开发“万能钥匙”APP,撬走3个亿

    来自:程序员头条 报道 又有 3 名程序员被抓!开发"万能钥匙"APP,撬走 3 亿! 前几天,据央视新闻报道,上海公安机关接到共享单车企业报案,随后破获了一起共享单车万能解锁 A ...

  5. 实现子数组和绝对值差最小 - Objective-C

    类似于背包问题,前提条件是数组全是正整数和0,先求和Sum,再从子数组中找出接近Sum/2的子数组 @interface TempState : NSObject @property (nonatom ...

  6. 【转】PHP中被忽略的性能优化利器:生成器.md

      PHP  如果是做Python或者其他语言的小伙伴,对于生成器应该不陌生.但很多PHP开发者或许都不知道生成器这个功能,可能是因为生成器是PHP 5.5.0才引入的功能,也可以是生成器作用不是很明 ...

  7. 手把手教你利用Jenkins持续集成iOS项目

    前言 众所周知,现在App的竞争已经到了用户体验为王,质量为上的白热化阶段.用户们都是很挑剔的.如果一个公司的推广团队好不容易砸了重金推广了一个APP,好不容易有了一些用户,由于一次线上的bug导致一 ...

  8. 【教程向】配置属于自己的vim

    新建Vim配置文件 Linux mkdir -/.vimrc 配置 常用设置 配置 功能 set number 设置行号 set systax on 高亮 colorscheme{主题} 设置颜色主题 ...

  9. Java GUI记账本(基于Mysql&&文件存储两种版本)

    */ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:text.java * 作者:常轩 * 微信公众号:Worldh ...

  10. webpack配置中环境变量-process.env. NODE_ENV

    背景 webpack有一特性就是可以让使用者灵活的在不同环境(开发环境,生产环境等)进行相应的特性的策略打包,比如: 是否使用反向代理使用接口,针对不同的静态资源(如图片等)是直接拷贝还是进行打包编译 ...