Spring IOC、DI、AOP原理和实现
(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接口和接口的实现类[java] view plaincopy
- package com.dao;
- public interface PersonDAO {
- public void save();
- }
2、创建一个Junit测试类[java] view plaincopy
- package com.dao.impl;
- import com.dao.PersonDAO;
- public class PersonDaoImpl implements PersonDAO {
- @Override
- public void save() {
- System.out.println("保存");
- }
- }
方法instanceSpring1为Spring中的实现用到ClassPathXmlApplicationContext类,要实现IOC的原理要定义自己[java] view plaincopy
- package com.test;
- import org.junit.Test;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- import com.dao.PersonDAO;
- import com.myUtil.MyClassPathXmlApplicationContext;
- import com.service.PersonService;
- public class PersonTest {
- @Test
- public void instanceSpring1(){
- /**
- *
- * spring 的实现
- */
- //IOC
- ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
- PersonDAO pd = (PersonDAO) ac.getBean("personDAO");
- pd.save();
- //DI
- PersonService ps = (PersonService) ac.getBean("personService");
- ps.save();
- }
- @Test
- public void instanceSpring2(){
- /**
- * 我的实现
- *
- */
- MyClassPathXmlApplicationContext mac = new MyClassPathXmlApplicationContext("beans.xml");
- PersonDAO mpd = (PersonDAO) mac.getBean("personDAO");
- mpd.save();
- //DI
- PersonService ps = (PersonService) mac.getBean("personService");
- ps.save();
- }
- }
的MyClassPathXmlApplicationContext首先读出beans.xml中的配置信息,通过反射机制实现bean,最后注入所需要的
bean。读取所的bean实体[java] view plaincopy
- package com.myUtil;
- import java.beans.Introspector;
- import java.beans.PropertyDescriptor;
- import java.lang.reflect.Method;
- import java.net.URL;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import org.dom4j.Document;
- import org.dom4j.Element;
- import org.dom4j.io.SAXReader;
- public class MyClassPathXmlApplicationContext {
- // xml所有的属性
- private ArrayList<BeanDefinition> beanDefinitions = new ArrayList<BeanDefinition>();
- // xml中所有的bean
- private Map<String, Object> sigletons = new HashMap<String, Object>();
- public MyClassPathXmlApplicationContext(String file) {
- readXml(file);
- instanceBeans();
- instanceObject();
- }
- /**
- * 注入
- */
- private void instanceObject() {
- for (BeanDefinition beanDefinition : beanDefinitions) {
- //判断有没有注入属性
- if (beanDefinition.getProperty() != null) {
- Object bean = sigletons.get(beanDefinition.getId());
- if (bean != null) {
- try {
- //得到被注入bean的所有的属性
- PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();
- //得到所有的注入bean属性
- for(PropertyDefinition propertyDefinition:beanDefinition.getProperty()){
- for(PropertyDescriptor propertyDescriptor:ps){
- if(propertyDescriptor.getName().equals(propertyDefinition.getName())){
- Method setter = propertyDescriptor.getWriteMethod();//获取set方法
- if(setter!=null){
- setter.setAccessible(true);//得到private权限
- //注入属性
- setter.invoke(bean, sigletons.get(propertyDefinition.getRef()));
- }
- break;
- }
- }
- }
- } catch (Exception e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
- }
- }
- /**
- * 实例所有的bean
- */
- private void instanceBeans() {
- for (int i = 0; i < beanDefinitions.size(); i++) {
- BeanDefinition bd = beanDefinitions.get(i);
- try {
- try {
- if (bd.getClassName() != null
- && !bd.getClassName().equals(""))
- sigletons.put(bd.getId(), Class.forName(
- bd.getClassName()).newInstance());
- } catch (InstantiationException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- } catch (ClassNotFoundException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
- /**
- * 读xml
- *
- * @param file
- */
- private void readXml(String file) {
- try {
- SAXReader reader = new SAXReader(); // 使用SAX方式解析XML
- URL xmlPath = this.getClass().getClassLoader().getResource(file);
- Document doc = reader.read(xmlPath);
- Element root = doc.getRootElement(); // 取得根节点
- List<Element> beans = root.elements();
- for (Element element : beans) {
- String id = element.attributeValue("id");// id;
- String clazz = element.attributeValue("class");
- BeanDefinition bd = new BeanDefinition(id, clazz);
- // 读取子元素
- if (element.hasContent()) {
- List<Element> propertys = element.elements();
- for (Element property : propertys) {
- String name = property.attributeValue("name");
- String ref = property.attributeValue("ref");
- PropertyDefinition pd = new PropertyDefinition(name,
- ref);
- bd.getProperty().add(pd);
- }
- }
- beanDefinitions.add(bd);
- }
- } catch (Exception e) {
- // TODO: handle exception
- }
- }
- /**
- * 通过名字得到bean
- *
- * @param str
- * @return
- */
- public Object getBean(String str) {
- return sigletons.get(str);
- }
- }
注入属性实体[java] view plaincopy
- package com.myUtil;
- import java.util.ArrayList;
- import java.util.List;
- public class BeanDefinition {
- private String id;
- private String className;
- private List<PropertyDefinition> property = new ArrayList<PropertyDefinition>();
- public BeanDefinition(String id, String className) {
- super();
- this.id = id;
- this.className = className;
- }
- public String getId() {
- return id;
- }
- public void setId(String id) {
- this.id = id;
- }
- public String getClassName() {
- return className;
- }
- public void setClassName(String className) {
- this.className = className;
- }
- public List<PropertyDefinition> getProperty() {
- return property;
- }
- public void setProperty(List<PropertyDefinition> property) {
- this.property = property;
- }
- }
业务接口和实现类[java] view plaincopy
- package com.myUtil;
- public class PropertyDefinition {
- private String name;
- private String ref;
- public PropertyDefinition(String name, String ref) {
- this.name = name;
- this.ref = ref;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getRef() {
- return ref;
- }
- public void setRef(String ref) {
- this.ref = ref;
- }
- }
[java] view plaincopy
- package com.service;
- public interface PersonService {
- public void save();
- }
beans.xml配置[java] view plaincopy
- package com.service.impl;
- import com.dao.PersonDAO;
- import com.service.PersonService;
- public class PersonServiceImpl implements PersonService{
- private PersonDAO pdo;
- public PersonDAO getPdo() {
- return pdo;
- }
- public void setPdo(PersonDAO pdo) {
- this.pdo = pdo;
- }
- @Override
- public void save() {
- pdo.save();
- }
- }
[java] view plaincopy
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
- <bean id="personDAO" class="com.dao.impl.PersonDaoImpl"></bean>
- <bean id="personService" class="com.service.impl.PersonServiceImpl">
- <property name="pdo" ref="personDAO"></property>
- </bean>
- </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定义的切面类
- package com.service;
- import org.aspectj.lang.annotation.Aspect;
- import org.aspectj.lang.annotation.Before;
- import org.aspectj.lang.annotation.Pointcut;
- @Aspect
- public class MyInterceptor {
- @Pointcut("execution (* com.serviceImpl.PersonServiceImpl.*(..))")
- private void myMethod(){};
- @Before("myMethod()")
- public void doAccessCheck(){
- System.out.println("before");
- }
- }
- package com.service;
- public class MyInterceptor2 {
- public void doAccessCheck(){
- System.out.println("before");
- }
- }
业务和接口
- package com.service;
- public interface PersonService {
- public void save(String name);
- public void update(String name);
- }
- package com.serviceImpl;
- import com.service.PersonService;
- public class PersonServiceImpl implements PersonService {
- @Override
- public void save(String name) {
- // TODO Auto-generated method stub
- System.out.println("保存");
- }
- @Override
- public void update(String name) {
- // TODO Auto-generated method stub
- System.out.println("修改");
- }
- }
简单做个方法前通知,其他的都一样。
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
- http://www.springframework.org/schema/aop
- http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
- <aop:aspectj-autoproxy/>
- <bean id="personServiceImpl" class="com.serviceImpl.PersonServiceImpl"></bean>
- <bean id="personInterceptor" class="com.service.MyInterceptor2"></bean>
- <aop:config>
- <aop:aspect id="asp" ref="personInterceptor">
- <aop:pointcut id="myCut" expression="execution (* com.serviceImpl.PersonServiceImpl.*(..))"/>
- <aop:before pointcut-ref="myCut" method="doAccessCheck"/>
- </aop:aspect>
- </aop:config>
- </beans>
测试类
- package com.test;
- import org.junit.Test;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- import com.service.PersonService;
- public class AopTest {
- @Test
- public void interceptorTest(){
- ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
- PersonService ps = (PersonService) ac.getBean("personServiceImpl");
- ps.save("aa");
- }
- }
Spring IOC、DI、AOP原理和实现的更多相关文章
- spring IOC DI AOP MVC 事务, mybatis 源码解读
demo https://gitee.com/easybao/aop.git spring DI运行时序 AbstractApplicationContext类的 refresh()方法 1: pre ...
- Spring+IOC(DI)+AOP概念及优缺点
Spring pring是一个轻量级的DI和AOP容器框架. 说它轻量级有一大部分原因是相对与EJB的(虽然本人从没有接触过EJB的应用),重要的是,Spring是非侵入式的,基于spring开发的应 ...
- 黑马-Spring(IOC&DI) AOP
IOC(控制翻转) 概念 把对象的创建.初始化.销毁等工作交给spring容器来做 案例 环境 步骤 1. 写一个HelloWorld类 2. 写一个配置文件 把hello类放到spring容 ...
- 170511、Spring IOC和AOP 原理彻底搞懂
Spring提供了很多轻量级应用开发实践的工具集合,这些工具集以接口.抽象类.或工具类的形式存在于Spring中.通过使用这些工具集,可以实现应用程序与各种开源技术及框架间的友好整合.比如有关jdbc ...
- Spring IOC DI AOP 的简单理解及应用
Spring两大特性:IOC 和AOP.IOC 控制反转,AOP 面向切面编程 spring 核心容器的主要组件时Bean工厂(BeanFactory) ,Bean 工厂使用控制反转模式来降低程序代码 ...
- coding++:Spring IOC/DI 实现原理
什么是 SpringIOC: spring ioc 指的是控制反转,IOC容器负责实例化.定位.配置应用程序中的对象及建立这些对象间的依赖.交由Spring容器统一进行管理,从而实现松耦合. “控制反 ...
- spring+IOC+DI+AOP优点分析(一)
Spring是什么: Spring是一个轻量级的DI和AOP容器框架. 说它轻量级有一大部分原因是相对与EJB的(虽然本人从没有接触过EJB的应用),重要的是,Spring是非侵入式的,基于sprin ...
- Spring ioc与aop的理解
一 spring的特点 1.降低了组件之间的耦合性 ,实现了软件各层之间的解耦 2.可以使用容易提供的众多服务,如事务管理,消息服务等 3.容器提供单例模式支持 4.容器提供了AOP技术,利用它很容易 ...
- 【转】spring - ioc和aop
[转]spring - ioc和aop 1.程序中为什么会用到spring的ioc和aop 2.什么是IOC,AOP,以及使用它们的好处,即详细回答了第一个问题 3.原理 关于1: a:我们平常使用对 ...
- J2EE进阶(十四)超详细的Java后台开发面试题之Spring IOC与AOP
J2EE进阶(十四)超详细的Java后台开发面试题之Spring IOC与AOP 前言 搜狐畅游笔试题中有一道问答题涉及到回答谈谈对Spring IOC与AOP的理解.特将相关内容进行整理. ...
随机推荐
- python pyqt6 QComboBox 设定下拉框背景颜色
设定QComboBox 的背景颜色,边框设定,以及下拉框的背景颜色以及边框设定, selection-background-color 不生效可忽略 xxx_source = QComboBox(se ...
- C#自定义控件—流动管道
C#用户控件之流动管道 如何绘制一个动态的流动管道(FlowPipe)? 分两步绘制 定义属性: 画布重绘: 主要技能: 管道的绘制(渐变色矩形) /// <summary> /// 画渐 ...
- .net core 依赖注入,运行报错 Cannot consume scoped 'xxx' service from singleton 'yyy'
这是因为 xxx 的生命周期是 AddScoped 注入的,而 yyy 的生命周期是 AddSingleton ,然后 yyy 这个单例的对象中,它又依赖了xxx 也就是说,单例注入的对象中依赖了 A ...
- ansible rpm包下载
Ansible2.9.18版本下载链接:https://pan.baidu.com/s/1dKlwtLWSOKoMkanW900n9Q 提取码:ansi 将软件上传至系统并解压安装: # tar -z ...
- CSS & JS Effect – 脉冲 Pulse Play Button
效果 参考 Youtube – Create a pulsing animation with CSS 重点 在背后做一个一样大的 div border 然后 animation scale up. ...
- ASP.NET Core C# 反射 & 表达式树 (第二篇)
前言 上一篇讲到了各种反射的操作方式, 这一篇主要说说如何找到类型. Type Information 在找类型的时候, 除了依据简单的 string 以外, 还会用到很多类型属性来做判断. 比如它是 ...
- C# + WPF 音频播放器 界面优雅,体验良好
前言 本文介绍一款使用 C# 与 WPF 开发的音频播放器,其界面简洁大方,操作体验流畅.该播放器支持多种音频格式(如 MP4.WMA.OGG.FLAC 等),并具备标记.实时歌词显示等功能. 另外, ...
- [CL-FOOL] CLOI 愚人赛的部分官方题解与小杂谈
小细节 谁会拿 Rank 奖励? 头图里有写哦. 发现没有,这里的问号是蓝色的,点进去可以进到彩蛋界面. 当然彩蛋界面也什么都没有,提交界面藏在下面的源码里. 那么交什么呢. CLOI 的文件里有一团 ...
- 2.2.2 PyTorch 2.0 GPU NVIDIA运行库的安装 ——CUDA+cuDNN安装教程
参考文章: https://blog.csdn.net/mbdong/article/details/121769951 CUDA download: https://developer.nvidia ...
- Nuxt.js 应用中的 app:rendered 钩子详解
title: Nuxt.js 应用中的 app:rendered 钩子详解 date: 2024/10/2 updated: 2024/10/2 author: cmdragon excerpt: 摘 ...