看完上一个章节,相信你已经掌握了一些思考的本领了。今天我们来聊一个新的话题。上一篇文章是一个简约的话题,希望简约而不简单。当然,如果觉得太浅了也请立刻告知猿人工厂君,可以考虑做一些调整来更好的帮助到你,另外真的很感谢大家的支持,和巨兽的斗争暂时进入僵持阶段,猿人工厂君已经说了,虽千万人,吾往矣。中间细节,猿人工厂君,会在方便的时候公开,程序猿鸭,且行且珍惜。

猿思考是一个原创系列文章,帮助你从一个小白快速掌握基础知识,很多基础知识,在于思考的变通,更多精彩内容,敬请大家关注公主号猿人工厂,点击猿人养成获取

IOC是Inversion ofControl的英文缩写,中文译名控制反转。控制反转?哈哈,是不是看起来怪怪的?控制反转,也是面向对象的一种编程原则,是一种编程思想。它是指将创建对象的管理权交给容器,由容器来装配和创建对象,从而降低代码之间的耦合度。IOC思想的实现,一般有两种方式,一种是依赖查找(Dependency Lookup)一种就是最常见的依赖注入(Dependency Injection) 。依赖查找是指程序运行时,程序使用容器提供的回调接口和上下文条件来查找资源和对象,从而让程序获得相应资源。这个种方式应用不是很多,需要应用服务器的支持,也就是JAVAEE规范的套路,比如JNDI,EJB...本文就不详细讨论了。而依赖注入(Dependency Injection)是什么呢?依赖注入是指,程序在运行时,程序不用做依赖的定位查询,提供普通的java方法去让容器决定依赖关系,容器全权负责程序使用对象的装配,把符合依赖关系的对象,通过属性或者是构造器的方式传递给依赖的对象。

我们看个简单的例子,我们有三个类:分别是TestServiceTestManager TestDao.其中TestService种有一个test()方法,调用了TestManager种的test()方法,而TestManager的test方法又调用了TestDao的test()方法。如果我们要调用TestService的test()方法,在正常情况下我们编写java代码,必然需要new TestService() newTestManager(), new TestDao().然后将TestManager对象作为TestService的一个属性传递给TestService(testService.setXXX或者是构造函数的方式传递),TestDao对象作为TestManager的一个属性,那么在使用TestService的类中,必然就需要在代码中import TestManager,

这样新编写的这个类代码依赖程度就高,耦合性强,不好维护。那现在改为依赖注入的方式,我们要使用TestService,就找容器拿TestService,容器提供的 TestService对象里已经存在TestManager对象了,那么我们使用TestService时,就只用在代码里import TestService就好了!新编写的类耦合性就没那么强了,易于维护多了。

那怎么去做到它呢?

不就是提供一个容器,获取对象嘛,只是获取的对象里的属性,已经由容器设置好了嘛。怎么办?通过名字创建对象!嗯,说白了,还是反射。下面我们来看一个小例子,实现简单的依赖注入。

先定义两个annotation:

package  com.pz.study.frame.ioc;import  java.lang.annotation.ElementType;
import  java.lang.annotation.Retention;
import  java.lang.annotation.RetentionPolicy;
import  java.lang.annotation.Target;/*** 用于注解需要由容器管理的类** @author pangzi**/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {String value() default"";}
package com.pz.study.frame.ioc;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** 用于注解需要注入的属性* @author pangzi**/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public@interfaceAutowared {}

定义一个简单的容器类:

package  com.pz.study.frame.ioc;import  java.io.File;
import  java.io.IOException;
import  java.io.InputStream;
import  java.lang.reflect.Field;
import  java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;public class ApplicationContext {public static final Map<String,Object> applicationContext = new ConcurrentHashMap<String, Object>();static {InputStream stream =ApplicationContext.class.getClassLoader().getResourceAsStream("ioc-frame.properties");Propertiesproperties = new Properties();try {properties.load(stream);} catch (IOException e) {e.printStackTrace();}StringpackageName=properties.getProperty("package").toString();try {instanceBean(packageName);} catch (Exception e) {e.printStackTrace();}}/*** 根据annotation上的名字获取对象* @param beanId* @return*/public static Object getBean(String beanId){returnapplicationContext.get(beanId);}/*** 创建包名下的对象并完成依赖注入* @param packageName* @throws Exception*/private static void instanceBean(StringpackageName) throws Exception {instanceByPackageName(packageName);autoWared();}// 获取指定包路径下使用了 ComponentAnnotationBean的实例private static void instanceByPackageName(String packageName) {try {List<String>classNames= getClassName(packageName,true);for(String className:classNames){Class<?>clazz = Class.forName(className);if (clazz.isAnnotationPresent(Component.class)) {clazz.getAnnotation(Component.class).value();applicationContext.put(clazz.getAnnotation(Component.class).value(), clazz.newInstance());}}} catch (Exception e) {e.printStackTrace();}}/*** 获取某包下所有类** @param packageName*            包名* @param childPackage*            是否遍历子包* @return类的完整名称*/private static List<String> getClassName(String packageName, boolean childPackage) {List<String> fileNames= null;ClassLoader loader = Thread.currentThread().getContextClassLoader();String packagePath =packageName.replace(".", "/");URL url =loader.getResource(packagePath);if (url != null) {String type =url.getProtocol();if (type.equals("file")) {fileNames = getClassNameByFile(url.getPath(), null, childPackage);}}return fileNames;}/*** 从项目文件获取某包下所有类** @param filePath*            文件路径* @param className*            类名集合* @param childPackage*            是否遍历子包* @return类的完整名称*/private static List<String> getClassNameByFile(String filePath,List<String> className, boolean childPackage) {List<String> myClassName= new ArrayList<>();File file = new File(filePath);File[] childFiles =file.listFiles();for (File childFile :childFiles) {if (childFile.isDirectory()) {if (childPackage) {myClassName.addAll(getClassNameByFile(childFile.getPath(),myClassName, childPackage));}} else {String childFilePath= childFile.getPath();if (childFilePath.endsWith(".class")) {childFilePath =childFilePath.substring(childFilePath.indexOf("/classes") + 9,childFilePath.lastIndexOf("."));childFilePath =childFilePath.replace("/", ".");myClassName.add(childFilePath);}}}return myClassName;}/*** 遍历map注入属性*/private static void autoWared() {Map<String, Object> map= applicationContext;try {for(StringbeanId:map.keySet()){Object obj=map.get(beanId);Field[] fields =obj.getClass().getDeclaredFields();for (Field field : fields) {if (field.isAnnotationPresent(Autowared.class)) {field.setAccessible(true);Object fieldObj= map.get(field.getName());field.set(obj,fieldObj);}}}}catch(Exception e){e.printStackTrace();}}
}

我们如果要使用容器创建的对象直接使用ApplicationContext.getBean()就好了。

接下来我们编写一单验证代码,使用我们的annotation和ApplicationContext提供的对象。

编写3个接口:

package com.pz.study.frame.test;public interface TestService {public void test();}
package com.pz.study.frame.test;public interface TestManager {public void test();}
package com.pz.study.frame.test;public interface TestDao {public void test();}
package com.pz.study.frame.test;import com.pz.study.frame.ioc.Autowared;
import com.pz.study.frame.ioc.Component;@Component(value="testService")
public class TestServiceImpl implements TestService {@Autowaredprivate TestManager testManager;public void test(){testManager.test();}}
package com.pz.study.frame.test;import com.pz.study.frame.ioc.Autowared;
import com.pz.study.frame.ioc.Component;@Component(value="testManager")
public class TestManagerImpl implements TestManager {@Autowaredprivate TestDao testDao;publicvoid test(){testDao.test();}}
package com.pz.study.frame.test;import com.pz.study.frame.ioc.Component;@Component(value="testDao")
public class TestDaoImpl implements TestDao {public void test(){System.out.println("ioc 小框架测试");}}

最后编写运行程序

package com.pz.study.frame.test;import com.pz.study.frame.ioc.ApplicationContext;public class TestIoc {public static void main(String args[]){TestService testService=(TestService) ApplicationContext.getBean("testService");testService.test();}}

运行程序,我们发现代码正确运行,而我们的程序只依赖了TestService这个接口,程序将需要依赖的对象交由自己定义的容器ApplicationContext去创建和装备。我们简单的实现了依赖注入的原理!

我建了一个群,群里有很多高手,大家可以一起讨论技术问题。

猿思考系列4——一文学会java的斗转星移相关推荐

  1. jsp中的url拼接的参数传递到controller乱码_猿蜕变系列5——一文搞懂Controller的花式编写...

    看过之前的执行流程,相信你对springMVC有了一定的认识.今天我们继续来学习springMVC相关的核心知识,帮助你快速起飞,完成蜕变. 每月底工厂君会根据后台记录筛选转发文章前三位的朋友,给与奖 ...

  2. java线程死锁 cpu 100%_一文学会Java死锁和CPU 100% 问题的排查技巧

    做一个积极的人 编码.改bug.提升自己 我有一个乐园,面向编程,春暖花开 工欲善其事,必先利其器 00 本文简介 作为一名搞技术的程序猿或者是攻城狮,想必你应该是对下面这两个问题有所了解,说不定你在 ...

  3. 一文学会Java死锁和CPU 100% 问题的排查技巧

    点击蓝色"程序猿DD"关注我 回复"资源"获取独家整理的学习资料! 00 本文简介 作为一名搞技术的程序猿或者是攻城狮,想必你应该是对下面这两个问题有所了解,说 ...

  4. 猿创征文|一文吃透JAVA初学者的开发工具

    ✅作者简介:热爱国学的Java后端开发者,修心和技术同步精进.

  5. ☀️苏州程序大白一文让你学会Java Servlet基础☀️《❤️记得收藏❤️》

    ☀️苏州程序大白一文让你学会Java Servlet基础☀️<❤️记得收藏❤️> 目录

  6. mysql中括号_【Java程序猿必备系列】MySQL知识点总结

    点击 隔壁王小猿 关注公众号获取更多精彩JAVA文章 1.数据库的组成 2.MySQL数据类型 MySQL支持多种类型,大致可以分为三类:数值.日期/时间和字符串(字符)类型. 2.1 数值类型 My ...

  7. java环境变量的配置_一文带你学会Java环境变量配置(小白向)

    很多人初学Java的时候,因为Java环境变量的配置卡的心烦意乱. 又有很多人百度上翻来翻去,得到的答案五花八门,让你头晕眼花. 你肯定也在想,不就是个环境变量的配置吗?为什么搜了那么多答案,依然不能 ...

  8. Java多线程干货系列(1):Java多线程基础

    转载自  Java多线程干货系列(1):Java多线程基础 前言 多线程并发编程是Java编程中重要的一块内容,也是面试重点覆盖区域,所以学好多线程并发编程对我们来说极其重要,下面跟我一起开启本次的学 ...

  9. 3个月Java速成记,一文记录Java学习过程

    ​3个月时间掌握Java基础知识,分享楼主的学习心路历程. 往期精选(欢迎转发~~) 如何看待程序员35岁职业危机? Java全套学习资料(14W字),耗时半年整理 我肝了三个月,为你写出了GO核心手 ...

最新文章

  1. EF 表联合查询 join
  2. leetcode -- 1091. 二进制矩阵中的最短路径
  3. linux QT 结束当前进程_软件特攻队|为什么 Qt 成为 c++ 界面编程的第一选择?
  4. SQLite | Case 子句
  5. 手哥架构宝典系列:支付系统2.0架构演进
  6. PHP define()的用法
  7. canvas实现抽奖插件—大转盘和九宫格
  8. 微软原生 Notepad 融入 VS Code 才是出路?
  9. PHP代码中解决出现中文乱码的问题
  10. 数组越界也可以这么巧~~~
  11. Microsoft.mshtml.dll 添加引用及类型选择错误问题解决办法
  12. Linux学习笔记——网络组成
  13. 【数字信号处理课程设计】基于MATLAB实现语音信号的采集与处理(偏重滤波)
  14. cnpack代码输入助手失效的解决办法
  15. HTML 事件参考手册:全局事件属性
  16. 二极管与门,或门,三极管整合
  17. android 带刻度的滑动条_Android实现滚动刻度尺效果
  18. 盘点华为系工控企业——中国A股上市公司最多的创业体系
  19. 虚拟机恢复初始化设置
  20. HTML5期末大作业:动漫人物介绍网站设计——柯南(5页) HTML+CSS+JavaScript 学生DW网页设计作业成品 学生动漫网页设计模板下载

热门文章

  1. python如何读取文件的每一行
  2. eclipse集成git回退到某个版本
  3. 追风筝的人:变质的友谊
  4. win7计划任务报该任务映像己损坏或己篡改
  5. 曙光计算机公司张涛,曙光创业协会“畅谈理想  规划人生”演讲比赛三等奖(文章)...
  6. mysql1819error
  7. 关于ffmpeg合成音视频报错的解决办法
  8. 如何找到python的环境变量_总算懂得如何设置python环境变量
  9. 一文带你了解IPsec协议
  10. 杨柳青旅游景点_天津必去景点之杨柳青古镇