开发基础
开发基础笔记
mybatis-plus通用的service方法
通过jenkins配置前后端自动打包及发布
mybatis-plus实现分页的方式
Java极客技术公众号PDF
狂神说SpringBoot
Hashids java 版使用
SpringBoot
1、Web快速开发
2、结果集的封装
3、集成MyBatis实现数据库操作
4、Springboot @Validated参数校验
5、SpringBoot全局异常处理
6、拦截器HandlerInterceptor
7、集成Swagger实现API自动生成
8、集成knife4j实现API自动生成
9、Springboot集成MyBatis-Plus快速入门
10、springboot自定义注解及AOP切面使用
11、使用Shiro实现登陆和权限认证,基于MyBatis
12、集成SpringSecurity实现授权认证
13、SpringBoot集成EasyExcel实现数据导入与导出
14、Spring Task定时任务的实现
15、Quartz快速上手与实践
16、如何用代码实现Spring IOC
17、SpringBoot集成JWT,实现接口的鉴权交互
SpringCloud
Nacos作为服务注册中心
seata1.6.1 结合springcloud实现分布锁的技术笔记
一些技术博客推荐
前端面试相关
看这一篇就够了
java.util包常用的类和接口
CountDownLatch介绍与使用
Common-lang3使用入门
Hutool简单使用入门
lombok 介绍及基本使用方法
git项目统计成员代码行数和提交的次数
mysql 逗号分隔的数据 like查询
使用sonar进行代码质量检查
线上使用jmeter进行压测的时候,使用Arthas诊断工具排查响应慢的接口
php结合phpstudy8、vscode开启xdebug进行代码调试
node-red使用入门
本文档使用 MrDoc 发布
-
+
首页
16、如何用代码实现Spring IOC
## 什么是IOC和DI IOC的起源程序员的春天spring框架中的概念,IOC (inversion of control)其意思是反转控制;那么什么是反转控制呢,我们常见的回答就是说我们的对象创建都交给IOC了,程序员从我们平常代码中大量的NEW代码解脱出来,消除了大量冗余的代码;举个比较形象的例子说明IOC做了什么; 举个例说明:拿我们做饭买菜举例: 没有IOC之前我们要做饭的话需要自己每天去菜市场买菜、用了IOC之后呢 我们只需要告诉菜贩子今天要吃什么菜,然后菜贩子把菜准备好送上门; 然而spring的IOC就相当于这个菜贩子,我们相当于当初要每天出门买菜的人,用了spring的IOC之后我们只需要告诉(通过配置xml 或注解)菜贩子我们需要什么菜(需要使用什么对象),然后它就会帮我们准备好(创建好对象); 然后用了IOC之后就伴随着DI (depend injection 依赖注入),什么叫依赖注入呢,结合上面买菜的例子,在我们买菜的时候告诉菜贩子什么样的菜需要放什么佐料,然后菜贩子会帮我们把对应菜和对应的佐料(大蒜、葱、姜)打好包准备好给我们,我们拿着对应打好包的菜就可以只接炒了不需要再去整理; ## 如何实现自己的IOC 通过上面我们知道了IOC的理念之后那我们接下来尝试整理下思路实现IOC的功能的大概思路和相关技术; 目标:把用户需要用到的对象实例化封装到一个容器中,提供容器公共的访问方法供开发人员使用; 整理思路:实现这个目标的过程需要做些什么 第一步: 创建自定义的注解(带有我们自定义注解的类才进行对象的实例化和装配); 第二步: 需要读取用户配置文件;(用户可自定义哪些包需要进行扫描bean的装配); 第三步: 扫描文件进行类加载(根据用户的配置扫描对应的包加载对应包里面的class放到一个容器里面); 第四步: 把扫描出来的class中带有自定义注解的类和属性分别进行实例化和属性注入; 第五步: 把实例化好的对象放到一个容器里并提供调用方法; 根据以上思路我们整理出来需要使用的技术有注解相关技术、配置文件加载技术、类加载技术、反射技术; **自己用最简单的代码实现一个Spring 的IOC功能。** 按照上面的思路我们已经大概了解了实现一个IOC所需要的功能步骤如下:  使用IDEA新建一个MAVEN项目,添加下面三个组件: ```xml <dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> <version>2.6</version> </dependency> <dependency> <groupId>commons-collections</groupId> <artifactId>commons-collections</artifactId> <version>3.2.2</version> </dependency> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.10</version> </dependency> ``` 新建application.properties 配置ioc.bean.scan属性,指定扫描哪个文件目录下的类。 在application.properties 文件中添加一个配置项: ioc.bean.scan=com.test.bean **定义MyComponet 注解 标注哪些类需要进行IOC管理** **定义MyAutowrited 注解 标注哪些属性进行依赖注入** ```java @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) @Documented public @interface MyAutowired { String value() default ""; } ``` **读取Properties文件(读取ioc.bean.scan的值)、类名首字母转小写工具方法(bean的名称默认是类名首字母小写)** ```java public class IocUtil { public static Properties getPropertyByName(String fileName) { InputStream is = null; Properties pro = null; try { is = IocUtil.class.getClassLoader().getResourceAsStream(fileName); pro = new Properties(); pro.load(is); } catch (IOException e) { e.printStackTrace(); } finally { if (is != null) { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } } return pro; } /** * 首字母转小写 * * @return */ public static String toLowercaseIndex(String name) { if (StringUtils.isNotEmpty(name)) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append(name.substring(0, 1).toLowerCase()); stringBuilder.append(name.substring(1, name.length())); return stringBuilder.toString(); } return null; } } ``` **定义需要进行IOC关联的类UserDao 、UserService ,放在bean目录下** ```java @MyComponent public class UserDao { public void findUser(String userName) { System.out.println("找到了一个用户名字叫:"+userName); } } ``` ```java @MyComponent public class UserService { @MyAutowired private UserDao userDao; public void findUser(String userName) { userDao.findUser(userName); } } ``` **IOC容器整体代码如下** ```java public class MyApplicationContext { //存储实例后的Bean容器 private Map<String, Object> beanMap = new ConcurrentHashMap<String, Object>(); //需要实例化的对象Class全路径名 private Set<String> classNameSet = new HashSet<String>(); public MyApplicationContext() { try { init(); } catch (Exception e) { e.printStackTrace(); } } /** * 根据Bean名称获取对象实例 * * @param name * @return */ public Object getBean(String name) throws NotFountBeanException { return beanMap.get(name); } /** * 初始化IOC容器 * @throws Exception */ public void init() throws Exception { //1、定位资源 String beanScanPath = getBeanScanPath("ioc.bean.scan"); //2、加载需要实例化的Class loadBeanClass(beanScanPath); //3、实例化bean registerBean(); //4、注入bean的属性 dependenceInjection(); } /** * 定位需要进行实例化JAVA类 * 读取application.properties 文件的ioc.bean.scan属性,得到需要扫描的文件夹 */ private String getBeanScanPath(String key) { Properties properties = IocUtil.getPropertyByName("application.properties"); return properties.get(key).toString(); } /** * 加载JAVAClass * 根据ioc.加载需要实例化的对象、并保存到classNameSet集合里 */ private void loadBeanClass(String packageName) { String filePath = packageName.replace(".", "/"); URL url = this.getClass().getClassLoader().getResource(filePath); System.out.println(url); //得到根文件夹 File rootFile = new File(url.getFile()); //遍历所有文件夹 if (rootFile != null) { for (File file : rootFile.listFiles()) { if (file.isDirectory()) { //文件夹则递归 loadBeanClass(packageName + "." + file.getName()); } else { if (file.getName().indexOf(".class") > 0) { //保存class类 classNameSet.add(packageName + "." + file.getName().replace(".class", "")); } } } } } /** * 注册实例化Bean * 实例化对象保存到beanMap容器 */ private void registerBean() throws Exception { if (CollectionUtils.isNotEmpty(classNameSet)) { for (String className : classNameSet) { //实例化对象放入beanMap Class clazz = Class.forName(className); MyComponent myComponent = (MyComponent) clazz.getAnnotation(MyComponent.class); if (myComponent == null) continue; //定义bean key名称 String beanName = (StringUtils.isEmpty(myComponent.value())) ? IocUtil.toLowercaseIndex(clazz.getSimpleName()) : myComponent.value(); beanMap.put(beanName, clazz.newInstance()); } } } /** * 依赖注入 */ private void dependenceInjection() throws Exception { if (MapUtils.isEmpty(beanMap)) return; for (Object o : beanMap.values()) { doInjection(o); } } /** * 对已经实例化的对象进行属性注入 */ private void doInjection(Object o) throws Exception { //获取类的属性,进行依赖注入 Field[] fields = o.getClass().getDeclaredFields(); if (ArrayUtils.isNotEmpty(fields)) { for (Field file : fields) { MyAutowired autowired = file.getAnnotation(MyAutowired.class); if (autowired != null) { //得到beanName 验证该Bean是否已经实例化了 String beanName = (StringUtils.isEmpty(autowired.value()))? IocUtil.toLowercaseIndex(file.getType().getSimpleName()):autowired.value(); //如果bean已经被实例化了,否则创建对象 if (!beanMap.containsKey(beanName)) { Class clazz = file.getType(); beanMap.put(beanName, clazz.newInstance()); } //调用对象set方法注入属性 file.setAccessible(true); file.set(o, beanMap.get(beanName)); //递归当前实例化的对象的属性注入 doInjection(beanMap.get(beanName)); } } } } } ``` 整体项目目录如下: <img src="/media/202301/spring_ioc.png" alt="1650098799631" /> gitee: https://gitee.com/seqier/spring_ioc
superadmin
2023年11月3日 17:22
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
分享
链接
类型
密码
更新密码