(1)Spring IOC原理

  IOC的意思是控件反转也就是由容器控制程序之间的关系,把控件权交给了外部容器,之前的写法,由程序代码直接操控,而现在控制权由应用代码中转到了外部容器,控制权的转移是所谓反转。网上有一个很形象的比喻:

我们是如何找女朋友的?常见的情况是,我们到处去看哪里有长得漂亮身材又好的mm,然后打听她们的兴趣爱好、qq号、电话号、ip号、iq号………,想办法认识她们,
投其所好送其所要,然后嘿嘿……这个过程是复杂深奥的,我们必须自己设计和面对每个环节。传统的程序开发也是如此,在一个对象中,如果要使用另外的对象,
就必须得到它(自己new一个,或者从JNDI中查询一个),使用完之后还要将对象销毁(比如Connection等),对象始终会和其他的接口或类藕合起来。
那么IoC是如何做的呢?有点像通过婚介找女朋友,在我和女朋友之间引入了一个第三者:婚姻介绍所。婚介管理了很多男男女女的资料,我可以向婚介提出一个列表,
告诉它我想找个什么样的女朋友,比如长得像李嘉欣,身材像林熙雷,唱歌像周杰伦,速度像卡洛斯,技术像齐达内之类的,然后婚介就会按照我们的要求,提供一个mm,
我们只需要去和她谈恋爱、结婚就行了。简单明了,如果婚介给我们的人选不符合要求,我们就会抛出异常。整个过程不再由我自己控制,而是有婚介这样一个类似容器的
机构来控制。Spring所倡导的开发方式就是如此,所有的类都会在spring容器中登记,告诉spring你是个什么东西,你需要什么东西,然后spring会在系统运行到适当的时候,
把你要的东西主动给你,同时也把你交给其他需要你的东西。所有的类的创建、销毁都由 spring来控制,也就是说控制对象生存周期的不再是引用它的对象,
而是spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被spring控制,所以这叫控制反转。  (2)DI(Dependency Injection,依赖注入)
        IoC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Injection,
依赖注入)来实现的。比如对象A需要操作数据库,以前我们总是要在A中自己编写代码来获得一个Connection对象,有了
spring我们就只需要告诉spring,A中需要一个Connection,至于这个Connection怎么构造,何时构造,A不需要知道。
在系统运行时,spring会在适当的时候制造一个Connection,然后像打针一样,注射到A当中,这样就完成了对各个对象之间关系
的控制。A需要依赖 Connection才能正常运行,而这个Connection是由spring注入到A中的,依赖注入的名字就这么来的。 下面来模拟下IOC和DI的实现原理。
项目的结构图如下:
1、首先定义DAO接口和接口的实现类
  1. package com.dao;
  2. public interface PersonDAO {
  3. public void save();
  4. }
  1. package com.dao.impl;
  2. import com.dao.PersonDAO;
  3. public class PersonDaoImpl implements PersonDAO {
  4. @Override
  5. public void save() {
  6. System.out.println("保存");
  7. }
  8. }
2、创建一个Junit测试类
  1. package com.test;
  2. import org.junit.Test;
  3. import org.springframework.context.ApplicationContext;
  4. import org.springframework.context.support.ClassPathXmlApplicationContext;
  5. import com.dao.PersonDAO;
  6. import com.myUtil.MyClassPathXmlApplicationContext;
  7. import com.service.PersonService;
  8. public class PersonTest {
  9. @Test
  10. public void instanceSpring1(){
  11. /**
  12. *
  13. * spring 的实现
  14. */
  15. //IOC
  16. ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
  17. PersonDAO pd = (PersonDAO) ac.getBean("personDAO");
  18. pd.save();
  19. //DI
  20. PersonService ps = (PersonService) ac.getBean("personService");
  21. ps.save();
  22. }
  23. @Test
  24. public void instanceSpring2(){
  25. /**
  26. * 我的实现
  27. *
  28. */
  29. MyClassPathXmlApplicationContext mac = new MyClassPathXmlApplicationContext("beans.xml");
  30. PersonDAO mpd = (PersonDAO) mac.getBean("personDAO");
  31. mpd.save();
  32. //DI
  33. PersonService ps = (PersonService) mac.getBean("personService");
  34. ps.save();
  35. }
  36. }
方法instanceSpring1为Spring中的实现用到ClassPathXmlApplicationContext类,要实现IOC的原理要定义自己
的MyClassPathXmlApplicationContext首先读出beans.xml中的配置信息,通过反射机制实现bean,最后注入所需要的
bean。
  1. package com.myUtil;
  2. import java.beans.Introspector;
  3. import java.beans.PropertyDescriptor;
  4. import java.lang.reflect.Method;
  5. import java.net.URL;
  6. import java.util.ArrayList;
  7. import java.util.HashMap;
  8. import java.util.List;
  9. import java.util.Map;
  10. import org.dom4j.Document;
  11. import org.dom4j.Element;
  12. import org.dom4j.io.SAXReader;
  13. public class MyClassPathXmlApplicationContext {
  14. // xml所有的属性
  15. private ArrayList<BeanDefinition> beanDefinitions = new ArrayList<BeanDefinition>();
  16. // xml中所有的bean
  17. private Map<String, Object> sigletons = new HashMap<String, Object>();
  18. public MyClassPathXmlApplicationContext(String file) {
  19. readXml(file);
  20. instanceBeans();
  21. instanceObject();
  22. }
  23. /**
  24. * 注入
  25. */
  26. private void instanceObject() {
  27. for (BeanDefinition beanDefinition : beanDefinitions) {
  28. //判断有没有注入属性
  29. if (beanDefinition.getProperty() != null) {
  30. Object bean = sigletons.get(beanDefinition.getId());
  31. if (bean != null) {
  32. try {
  33. //得到被注入bean的所有的属性
  34. PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();
  35. //得到所有的注入bean属性
  36. for(PropertyDefinition propertyDefinition:beanDefinition.getProperty()){
  37. for(PropertyDescriptor propertyDescriptor:ps){
  38. if(propertyDescriptor.getName().equals(propertyDefinition.getName())){
  39. Method setter = propertyDescriptor.getWriteMethod();//获取set方法
  40. if(setter!=null){
  41. setter.setAccessible(true);//得到private权限
  42. //注入属性
  43. setter.invoke(bean, sigletons.get(propertyDefinition.getRef()));
  44. }
  45. break;
  46. }
  47. }
  48. }
  49. } catch (Exception e) {
  50. // TODO Auto-generated catch block
  51. e.printStackTrace();
  52. }
  53. }
  54. }
  55. }
  56. }
  57. /**
  58. * 实例所有的bean
  59. */
  60. private void instanceBeans() {
  61. for (int i = 0; i < beanDefinitions.size(); i++) {
  62. BeanDefinition bd = beanDefinitions.get(i);
  63. try {
  64. try {
  65. if (bd.getClassName() != null
  66. && !bd.getClassName().equals(""))
  67. sigletons.put(bd.getId(), Class.forName(
  68. bd.getClassName()).newInstance());
  69. } catch (InstantiationException e) {
  70. // TODO Auto-generated catch block
  71. e.printStackTrace();
  72. } catch (IllegalAccessException e) {
  73. // TODO Auto-generated catch block
  74. e.printStackTrace();
  75. }
  76. } catch (ClassNotFoundException e) {
  77. // TODO Auto-generated catch block
  78. e.printStackTrace();
  79. }
  80. }
  81. }
  82. /**
  83. * 读xml
  84. *
  85. * @param file
  86. */
  87. private void readXml(String file) {
  88. try {
  89. SAXReader reader = new SAXReader(); // 使用SAX方式解析XML
  90. URL xmlPath = this.getClass().getClassLoader().getResource(file);
  91. Document doc = reader.read(xmlPath);
  92. Element root = doc.getRootElement(); // 取得根节点
  93. List<Element> beans = root.elements();
  94. for (Element element : beans) {
  95. String id = element.attributeValue("id");// id;
  96. String clazz = element.attributeValue("class");
  97. BeanDefinition bd = new BeanDefinition(id, clazz);
  98. // 读取子元素
  99. if (element.hasContent()) {
  100. List<Element> propertys = element.elements();
  101. for (Element property : propertys) {
  102. String name = property.attributeValue("name");
  103. String ref = property.attributeValue("ref");
  104. PropertyDefinition pd = new PropertyDefinition(name,
  105. ref);
  106. bd.getProperty().add(pd);
  107. }
  108. }
  109. beanDefinitions.add(bd);
  110. }
  111. } catch (Exception e) {
  112. // TODO: handle exception
  113. }
  114. }
  115. /**
  116. * 通过名字得到bean
  117. *
  118. * @param str
  119. * @return
  120. */
  121. public Object getBean(String str) {
  122. return sigletons.get(str);
  123. }
  124. }
读取所的bean实体
  1. package com.myUtil;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. public class BeanDefinition {
  5. private String id;
  6. private String className;
  7. private List<PropertyDefinition> property = new ArrayList<PropertyDefinition>();
  8. public BeanDefinition(String id, String className) {
  9. super();
  10. this.id = id;
  11. this.className = className;
  12. }
  13. public String getId() {
  14. return id;
  15. }
  16. public void setId(String id) {
  17. this.id = id;
  18. }
  19. public String getClassName() {
  20. return className;
  21. }
  22. public void setClassName(String className) {
  23. this.className = className;
  24. }
  25. public List<PropertyDefinition> getProperty() {
  26. return property;
  27. }
  28. public void setProperty(List<PropertyDefinition> property) {
  29. this.property = property;
  30. }
  31. }
注入属性实体
  1. package com.myUtil;
  2. public class PropertyDefinition {
  3. private String name;
  4. private String ref;
  5. public PropertyDefinition(String name, String ref) {
  6. this.name = name;
  7. this.ref = ref;
  8. }
  9. public String getName() {
  10. return name;
  11. }
  12. public void setName(String name) {
  13. this.name = name;
  14. }
  15. public String getRef() {
  16. return ref;
  17. }
  18. public void setRef(String ref) {
  19. this.ref = ref;
  20. }
  21. }
业务接口和实现类
  1. package com.service;
  2. public interface PersonService {
  3. public void save();
  4. }
  1. package com.service.impl;
  2. import com.dao.PersonDAO;
  3. import com.service.PersonService;
  4. public class PersonServiceImpl implements PersonService{
  5. private PersonDAO pdo;
  6. public PersonDAO getPdo() {
  7. return pdo;
  8. }
  9. public void setPdo(PersonDAO pdo) {
  10. this.pdo = pdo;
  11. }
  12. @Override
  13. public void save() {
  14. pdo.save();
  15. }
  16. }
beans.xml配置
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
  6. <bean id="personDAO" class="com.dao.impl.PersonDaoImpl"></bean>
  7. <bean id="personService" class="com.service.impl.PersonServiceImpl">
  8. <property name="pdo" ref="personDAO"></property>
  9. </bean>
  10. </beans>

(3)AOP面向切面

AOP是OOP的延续,是(Aspect Oriented Programming)的缩写,意思是面向切面编程。要理解AOP首先得弄明白代理的概念。对于代理看下点击打开链接这篇文章。

AOP(Aspect Orient Programming),作为面向对象编程的一种补充,广泛应用于处理一些具有横切性质的系统级服务,如事务管理、安全检查、缓存、对象池管理等。 AOP 实现的关键就在于 AOP 框架自动创建的 AOP 代理,AOP 代理则可分为静态代理和动态代理两大类,其中静态代理是指使用 AOP 框架提供的命令进行编译,从而在编译阶段就可生成 AOP 代理类,因此也称为编译时增强;而动态代理则在运行时借助于 JDK 动态代理、CGLIB 等在内存中"临时"生成 AOP 动态代理类,因此也被称为运行时增强。

知道这些其他的就是些配置了。

简单的实现annotations和xml对AOP的实现。

首先看下目录结构

MyInterceptor、MyInterceptor2分别是以annotations和xml定义的切面类

[java] view
plain
copy

  1. package com.service;
  2. import org.aspectj.lang.annotation.Aspect;
  3. import org.aspectj.lang.annotation.Before;
  4. import org.aspectj.lang.annotation.Pointcut;
  5. @Aspect
  6. public class MyInterceptor {
  7. @Pointcut("execution (* com.serviceImpl.PersonServiceImpl.*(..))")
  8. private void myMethod(){};
  9. @Before("myMethod()")
  10. public void doAccessCheck(){
  11. System.out.println("before");
  12. }
  13. }
[java] view
plain
copy

  1. package com.service;
  2. public class MyInterceptor2 {
  3. public void doAccessCheck(){
  4. System.out.println("before");
  5. }
  6. }

业务和接口

[java] view
plain
copy

  1. package com.service;
  2. public interface PersonService {
  3. public void save(String name);
  4. public void update(String name);
  5. }
[java] view
plain
copy

  1. package com.serviceImpl;
  2. import com.service.PersonService;
  3. public class PersonServiceImpl implements PersonService {
  4. @Override
  5. public void save(String name) {
  6. // TODO Auto-generated method stub
  7. System.out.println("保存");
  8. }
  9. @Override
  10. public void update(String name) {
  11. // TODO Auto-generated method stub
  12. System.out.println("修改");
  13. }
  14. }

简单做个方法前通知,其他的都一样。

[java] view
plain
copy

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
  6. http://www.springframework.org/schema/aop
  7. http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
  8. <aop:aspectj-autoproxy/>
  9. <bean id="personServiceImpl" class="com.serviceImpl.PersonServiceImpl"></bean>
  10. <bean id="personInterceptor" class="com.service.MyInterceptor2"></bean>
  11. <aop:config>
  12. <aop:aspect id="asp" ref="personInterceptor">
  13. <aop:pointcut id="myCut" expression="execution (* com.serviceImpl.PersonServiceImpl.*(..))"/>
  14. <aop:before pointcut-ref="myCut" method="doAccessCheck"/>
  15. </aop:aspect>
  16. </aop:config>
  17. </beans>

测试类

[java] view
plain
copy

  1. package com.test;
  2. import org.junit.Test;
  3. import org.springframework.context.ApplicationContext;
  4. import org.springframework.context.support.ClassPathXmlApplicationContext;
  5. import com.service.PersonService;
  6. public class AopTest {
  7. @Test
  8. public void interceptorTest(){
  9. ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
  10. PersonService ps = (PersonService) ac.getBean("personServiceImpl");
  11. ps.save("aa");
  12. }
  13. }

Spring IOC、DI、AOP原理和实现的更多相关文章

  1. spring IOC DI AOP MVC 事务, mybatis 源码解读

    demo https://gitee.com/easybao/aop.git spring DI运行时序 AbstractApplicationContext类的 refresh()方法 1: pre ...

  2. Spring+IOC(DI)+AOP概念及优缺点

    Spring pring是一个轻量级的DI和AOP容器框架. 说它轻量级有一大部分原因是相对与EJB的(虽然本人从没有接触过EJB的应用),重要的是,Spring是非侵入式的,基于spring开发的应 ...

  3. 黑马-Spring(IOC&DI) AOP

    IOC(控制翻转) 概念 把对象的创建.初始化.销毁等工作交给spring容器来做 案例 环境 步骤 1.  写一个HelloWorld类 2.  写一个配置文件   把hello类放到spring容 ...

  4. 170511、Spring IOC和AOP 原理彻底搞懂

    Spring提供了很多轻量级应用开发实践的工具集合,这些工具集以接口.抽象类.或工具类的形式存在于Spring中.通过使用这些工具集,可以实现应用程序与各种开源技术及框架间的友好整合.比如有关jdbc ...

  5. Spring IOC DI AOP 的简单理解及应用

    Spring两大特性:IOC 和AOP.IOC 控制反转,AOP 面向切面编程 spring 核心容器的主要组件时Bean工厂(BeanFactory) ,Bean 工厂使用控制反转模式来降低程序代码 ...

  6. coding++:Spring IOC/DI 实现原理

    什么是 SpringIOC: spring ioc 指的是控制反转,IOC容器负责实例化.定位.配置应用程序中的对象及建立这些对象间的依赖.交由Spring容器统一进行管理,从而实现松耦合. “控制反 ...

  7. spring+IOC+DI+AOP优点分析(一)

    Spring是什么: Spring是一个轻量级的DI和AOP容器框架. 说它轻量级有一大部分原因是相对与EJB的(虽然本人从没有接触过EJB的应用),重要的是,Spring是非侵入式的,基于sprin ...

  8. Spring ioc与aop的理解

    一 spring的特点 1.降低了组件之间的耦合性 ,实现了软件各层之间的解耦 2.可以使用容易提供的众多服务,如事务管理,消息服务等 3.容器提供单例模式支持 4.容器提供了AOP技术,利用它很容易 ...

  9. 【转】spring - ioc和aop

    [转]spring - ioc和aop 1.程序中为什么会用到spring的ioc和aop 2.什么是IOC,AOP,以及使用它们的好处,即详细回答了第一个问题 3.原理 关于1: a:我们平常使用对 ...

  10. J2EE进阶(十四)超详细的Java后台开发面试题之Spring IOC与AOP

    J2EE进阶(十四)超详细的Java后台开发面试题之Spring IOC与AOP 前言   搜狐畅游笔试题中有一道问答题涉及到回答谈谈对Spring IOC与AOP的理解.特将相关内容进行整理.    ...

随机推荐

  1. python pyqt6 QComboBox 设定下拉框背景颜色

    设定QComboBox 的背景颜色,边框设定,以及下拉框的背景颜色以及边框设定, selection-background-color 不生效可忽略 xxx_source = QComboBox(se ...

  2. C#自定义控件—流动管道

    C#用户控件之流动管道 如何绘制一个动态的流动管道(FlowPipe)? 分两步绘制 定义属性: 画布重绘: 主要技能: 管道的绘制(渐变色矩形) /// <summary> /// 画渐 ...

  3. .net core 依赖注入,运行报错 Cannot consume scoped 'xxx' service from singleton 'yyy'

    这是因为 xxx 的生命周期是 AddScoped 注入的,而 yyy 的生命周期是 AddSingleton ,然后 yyy 这个单例的对象中,它又依赖了xxx 也就是说,单例注入的对象中依赖了 A ...

  4. ansible rpm包下载

    Ansible2.9.18版本下载链接:https://pan.baidu.com/s/1dKlwtLWSOKoMkanW900n9Q 提取码:ansi 将软件上传至系统并解压安装: # tar -z ...

  5. CSS & JS Effect – 脉冲 Pulse Play Button

    效果 参考 Youtube – Create a pulsing animation with CSS 重点 在背后做一个一样大的 div border 然后 animation scale up. ...

  6. ASP.NET Core C# 反射 & 表达式树 (第二篇)

    前言 上一篇讲到了各种反射的操作方式, 这一篇主要说说如何找到类型. Type Information 在找类型的时候, 除了依据简单的 string 以外, 还会用到很多类型属性来做判断. 比如它是 ...

  7. C# + WPF 音频播放器 界面优雅,体验良好

    前言 本文介绍一款使用 C# 与 WPF 开发的音频播放器,其界面简洁大方,操作体验流畅.该播放器支持多种音频格式(如 MP4.WMA.OGG.FLAC 等),并具备标记.实时歌词显示等功能. 另外, ...

  8. [CL-FOOL] CLOI 愚人赛的部分官方题解与小杂谈

    小细节 谁会拿 Rank 奖励? 头图里有写哦. 发现没有,这里的问号是蓝色的,点进去可以进到彩蛋界面. 当然彩蛋界面也什么都没有,提交界面藏在下面的源码里. 那么交什么呢. CLOI 的文件里有一团 ...

  9. 2.2.2 PyTorch 2.0 GPU NVIDIA运行库的安装 ——CUDA+cuDNN安装教程

    参考文章: https://blog.csdn.net/mbdong/article/details/121769951 CUDA download: https://developer.nvidia ...

  10. Nuxt.js 应用中的 app:rendered 钩子详解

    title: Nuxt.js 应用中的 app:rendered 钩子详解 date: 2024/10/2 updated: 2024/10/2 author: cmdragon excerpt: 摘 ...