理解Spring的AOP和Ioc/DI就这么简单

一、什么叫Ioc、DI
Ioc:Inversion of Control —— 控制反转

DI:Dependency Injection —— 依赖注入

其实这两个概念本质上是没有区别的,那我们先来看看什么叫做Ioc?

假设这么一个场景:

在A类中调用B类的方法,那么我们就称 A依赖B,B为被依赖(对象),相信这点大家能够理解。

传统做法:

(1)直接在A(方法)中new出B类对象,然后调用B类方法 —— 硬编码耦合;

(2)通过简单工厂获取B类对象,然后调用B类的方法 —— 摆脱了与B的耦合,却又与工厂产生了耦合;

以上两种做法,都是在A中主动去new或调用简单工厂的方法产生B的对象,注意,关键字是“主动”

Spring框架

在spring中,B的实例对象被看成Bean对象,这个Bean对象由spring容器进行创建和管理,当我们在配置文件中配置<Bean>下的<property>子元素时,spring就会自动执行在A中对B对象的setter方法(即A中需要有对B对象的setter方法),如此一来,A获取B的实例对象就不是由自己主动去获取,而是被动接受spring给它设值,那么,这个主动变为被动,就可以理解为“控制反转”。

而另一种说法,从spring容器的角度上看,它负责把A的依赖对象B(B是被依赖对象)注入给了A,所以我们可以理解为“依赖注入”

(spring中依赖注入的方式可不止调用setter方法一种,还有通过调用构造器的方式来实现,这里只是为了说明Ioc和DI,就不再累赘了)

<bean id="userAction" class="com.router.action.UserAction" scope="prototype">
<!-- 注入Service -->
<property name="userService" ref="userService" />
</bean>
<bean id="userService" class="com.router.serviceimpl.UserServiceImpl"></bean>

// 注入service
private UserService userService;

public void setUserService(UserService userService) {
this.userService = userService;
}

以上代码,spring通过<property>元素(当然内部有它的实现方法)自动调用userService的setter方法,userAction中就获得了userService对象了。

那么我们来分析一下,通过使用spring的依赖注入功能,是怎么达到解耦了呢?

首先,我们的编程是面向接口编程(在实际开发开发中也是需要我们面向接口编程的),上面代码中的UserService就是一个接口,UserServiceImpl就是其中的一个实现类。那么当我们通过直接new的方式创建对象,则是UserService userService = new UserServiceImpl();,这句话是写在源代码里头中的,当实现类UserServiceImpl内部放生改变时,或者是不再想使用这个类,而是另一个新的实现类(比如说是UserServiceImpl2),那么我们就得在源代码中将UserService userService = new UserServiceImpl2();,而以后或许需求还会变,那么就得不停地修改源代码。

而使用spring框架后,只需在配置文件中的<Bean>配置所需要的相应接口的实现方法,然后通过setter方法注入进去即可,setter方法不管以后变不变实现类,都不需要修改,要改的只是在spring的配置文件中改掉实现类的全路径即可,如此看来,这确实是达到了解耦!

二、什么是AOP?
AOP —— Asepct-Orentid-Programming,面向切面编程

那么我们该怎么理解AOP呢?我们可以通过OOP —— 面向对象编程来进行比较分析

相信大家对于OOP的理解不难,就以人(people)来说,我们就可以把它看做一类对象,people有身高、体重、年龄等属性,也有跑步、吃饭、睡觉、娱乐等行为,把这些属于people的属性和行为封装在people类中,然后以统一调用的方式(创建一个people类实例对象,通过这个对象实例来调用这些属性和行为)就叫做OOP思想,OOP给我们的感觉就是结构清晰,高内聚,易维护等。这些属于一种从上到下的关系(即这个类封装的所有属性和方法都是属于people的),而我们的AOP思想就是一种从左到右的关系,以切入的方式将业务逻辑功能应用到每一层结构中(可以理解为类方法,类方法也是一种对象的行为实现)。举个例子,people也可以分为少年、青年、中年、和老年,这几类人除了拥有自己的属性和行为外,生活中,或许还需要去医院看病,但是医院看病这一个逻辑业务功能并不是属于哪一类,而是谁生病了,才需要到医院看病,而基于面向对象编程的思想,我们是不可能把这一个业务逻辑行为加到每一个类中的,这不符合OOP思想,而这个就是AOP所做也可以做到事情了,AOP就是把医院看病这一个业务逻辑功能抽取出来,然后动态把这个功能注入到需要的方法(或行为)中,以后,不管是谁需要看病,就到医院这个第三方机构看病(AOP就是相当于把这个第三方机构独立出来),这样从业务逻辑角度上,AOP达到了更近一步的的解耦,所以我们也称AOP是对OOP的完善和增强。

而我们的编程中,常用到AOP的就是安全校验、日志操作、事务操作等,接下来一张图认识AOP思想

AOP就是使用上图所示的“横切”技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。Aop 的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。正如Avanade公司的高级方案构架师Adam Magee所说,AOP的核心思想就是“将应用程序中的商业逻辑同对其提供支持的通用服务进行分离。”

AOP的相关术语

1.通知(Advice)
  就是你想要的功能,也就是上面说的 安全,事务,日志等。你给先定义好,然后在想用的地方用一下。

2.连接点(JoinPoint)
  这个更好解释了,就是spring允许你使用通知的地方,那可真就多了,基本每个方法的前,后(两者都有也行),或抛出异常时都可以是连接点,spring只支持方法连接点,其他如aspectJ还可以让你在构造器或属性注入时都行,不过那不是咱关注的,只要记住,和方法有关的前前后后(抛出异常),都是连接点。

3.切入点(Pointcut)
  上面说的连接点的基础上,来定义切入点,你的一个类里,有15个方法,那就有几十个连接点了对把,但是你并不想在所有方法附近都使用通知(使用叫织入,以后再说),你只想让其中的几个,在调用这几个方法之前,之后或者抛出异常时干点什么,那么就用切点来定义这几个方法,让切点来筛选连接点,选中那几个你想要的方法。

4.切面(Aspect)
  切面是通知和切入点的结合。现在发现了吧,没连接点什么事情,连接点就是为了让你好理解切点,搞出来的,明白这个概念就行了。通知说明了干什么和什么时候干(什么时候通过方法名中的before,after,around等就能知道),而切入点说明了在哪干(指定到底是哪个方法),这就是一个完整的切面定义。

5.引入(introduction)
  允许我们向现有的类添加新方法属性。这不就是把切面(也就是新方法属性:通知定义的)用到目标类中吗

6.目标(target)
  引入中所提到的目标类,也就是要被通知的对象,也就是真正的业务逻辑,他可以在毫不知情的情况下,被咱们织入切面。而自己专注于业务本身的逻辑。

7.代理(proxy)
  怎么实现整套aop机制的,都是通过代理,也就是说,AOP的实现原理是基于动态代理实现的。

8.织入(weaving)
  把切面应用到目标对象来创建新的代理对象的过程。

在此笔者建议,如果不是很了解java动态代理的代理,可以先去熟悉下动态代理,这样能更好的理解AOP的实现原理

可看笔者另一篇文章 静态代理与动态代理

AOP应用实例1 —— 动态代理的形式模拟AOP

(以下应用实例都是基于接口编程,笔者就不示出接口了)

public class UserAImpl implements UserA{

@Override
public void save() {
System.out.println("正在保存A类用户……");

}

@Override
public void update() {
System.out.println("正在更新A类用户……");

}

}

public class UserBImpl implements UserB {

@Override
public void save() {
System.out.println("正在保存B类用户……");

}

@Override
public void update() {
System.out.println("正在更新B类用户……");

}

}

AOP业务增强(通知)类

public class DataValidateImpl implements DataValidate {

@Override
public void validate() {
System.out.println("正在进行数据校验……");
System.out.println("数据校验完毕!");

}

@Override
public void advice() {
System.out.println("操作成功");

}

}

代理工厂类

public class ProxyFactoryImpl implements ProxyFactory {

//单例模式创建工厂
private static ProxyFactoryImpl proxyFactorySingleton;

private ProxyFactoryImpl() {}

public static ProxyFactoryImpl getProxyFactorySingleton() {
if (proxyFactorySingleton == null) {
proxyFactorySingleton = new ProxyFactoryImpl();
}
return proxyFactorySingleton;
}

@Override
public Object newProxyInstance(Object obj, InvocationHandler handler) {

return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(),
handler);
}

}

测试类

public class AOPTest {

public static void main(String[] args) {
ProxyFactoryImpl proxyFactory = ProxyFactoryImpl.getProxyFactorySingleton();

//操作A类用户数据
UserA ua = (UserA) proxyFactory.newProxyInstance(new UserAImpl(),
new UserAHandler(new UserAImpl(), new DataValidateImpl()));
//得到的是代理对象
System.out.println(ua.getClass().getName());

ua.save();
ua.update();

System.out.println("********************");

//操作B类用户数据
UserB ub = (UserB) proxyFactory.newProxyInstance(new UserBImpl(),
new UserBHandler(new UserBImpl(), new DataValidateImpl()));

//得到的是代理对象
System.out.println(ub.getClass().getName());

ub.save();
ub.update();

//如果不用代理来调用,就是这样的结果
System.out.println("======================");
UserB ub2 = new UserBImpl();
ub2.save();
ub2.update();
}
}

运行结果:

AOP应用实例 —— spring注解方式使用AOP

User类

public class User {

public void addUser(){
System.out.println("添加成功!");
}
}
增强类

@Aspect
public class MyUser {

@Before(value = "execution(* com.xian.entity.User.*(..))")
public void before() {
System.out.println("before……");
}

@After(value = "execution(* com.xian.entity.User.*(..))")
public void after() {
System.out.println("after……");
}
}
配置文件
<bean id="user" class="com.xian.entity.User"></bean>
<bean id="myUser" class="com.xian.entity.MyUser"></bean>

<!-- 配置文件方式使用AOP -->
<!-- <aop:config>
配置切入点
<aop:pointcut expression="execution(* com.xian.entity.User.*(..))" id="userPC1"/>

配置切面
将增强使用于方法上

<aop:aspect ref="myUser">
配置增强的类型
<aop:before method="before" pointcut-ref="userPC1"/>
<aop:after method="after" pointcut-ref="userPC1"/>
</aop:aspect>
</aop:config> -->

<!-- 注解方式使用AOP -->
<!-- 开启AOP代理 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

测试类
public class UserTest {
//private static Logger userLog = Logger.getLogger(User.class);
@Test
public void testUser(){

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) context.getBean("user");//通过bean容器获得 的user其实只是一个代理对象
User user2 = new User();
System.out.println(user == user2);
MyUser mu = (MyUser) context.getBean("myUser");
//userLog.info("开始调用User的Add方法……");
user.addUser();//把这里变成user2来调用add,就不会执行切面的增强逻辑功能了

//userLog.info("正常结束……");
}
}

运行结果:

---------------------
作者:回梦游先
来源:CSDN
原文:https://blog.csdn.net/h_xiao_x/article/details/72774496
版权声明:本文为博主原创文章,转载请附上博文链接!

原文地址:https://www.cnblogs.com/lonske/p/10172342.html

时间: 2024-08-12 02:44:55

理解Spring的AOP和Ioc/DI就这么简单的相关文章

Spring之Aop与Ioc

用Spring用了这么久,也该找个时间总结总结,这里我并没有把Aop和Ioc分开讲. 首先概述一下Spring,Spring是一款设计非常好的解耦框架,无侵入性,可以整合其它很多框架,比如常用的Struts,Hibernate,Mybatis或者Ibatis等,由此可以解决企业开发的复杂性,其核心的两个东西,就是AOP和IOC. Spring包含了7个模块,每个模块可以独立存在 每个模块的作用如下(这里参考的其它博客.原文地址:http://www.ibm.com/developerworks/

spring、AOP、IOC

对spring的理解是什么? spring: 1.开源框架: 2.IOC(控制反转),将类的创建和依赖关系写在配置文件里,由配置文件注入,实现了松耦合: 3.AOP将安全.事务等于程序逻辑相对独立的功能抽取出来,利用spring的配置文件将这些功能插进去,实现了按照方面编程,提高了复用性. spring是一个轻型容器,其核心是bean工厂,用以构造我们所需要的Model.在此基础之上,spring提供了aop的实现,用他来提供非管理环境下申明方式的事务.安全等服务:对bean工厂的扩张appli

spring 学习 AOP和IOC

自11开始接触三大框架,至今已俞5载, 当时风光无限的ssh,现在还在被广泛使用,并有扩大之势的只有spring了 spring主要特性,是广为使用的AOP(面向切面)和IOC(控制反转) 1.其中,IOC(控制反转)也叫依赖注入,使用最是广泛 基本概念是:不创建对象,但是描述创建它们的方式.在代码中不直接与对象和服务连接,但在配置文件中描述哪一个组件需要哪一项服务.容器 (在 Spring 框架中是 IOC 容器) 负责将这些联系在一起. 就是通过在代码中大量使用接口,并为所有参数编写get,

Spring中AOP和IOC

什么是DI机制? 依赖注入(Dependecy Injection)和控制反转(Inversion of Control)是同一个概念,具体的讲:当某个角色 需要另外一个角色协助的时候,在传统的程序设计过程中,通常由调用者来创建被调用者的实例.但在spring中 创建被调用者的工作不再由调用者来完成,因此称为控制反转.创建被调用者的工作由spring来完成,然后注入调用者 因此也称为依赖注入. spring以动态灵活的方式来管理对象 , 注入的两种方式,设置注入和构造注入. 设置注入的优点:直观

AOP、静态代理、JDK动态代理、CGLIB动态代理、Spring实现AOP、IOC+AOP

一.为什么需要代理模式 假设需实现一个计算的类Math.完成加.减.乘.除功能,如下所示: 1 package com.zhangguo.Spring041.aop01; 2 3 public class Math { 4 //加 5 public int add(int n1,int n2){ 6 int result=n1+n2; 7 System.out.println(n1+"+"+n2+"="+result); 8 return result; 9 } 1

Spring中AOP和IOC深入理解

spring框架 Spring框架是由于软件开发的复杂性而创建的.Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情.然而,Spring的用途不仅仅限于服务器端的开发.从简单性.可测试性和松耦合性的角度而言,绝大部分Java应用都可以从Spring中受益. ◆目的:解决企业应用开发的复杂性 ◆功能:使用基本的JavaBean代替EJB,并提供了更多的企业应用功能 ◆范围:任何Java应用 Spring是一个轻量级控制反转(IoC)和面向切面(AOP)的容器框架. Spr

如何理解IoC/DI

IoC:Inversion of Control,控制反转DI:Dependency Injection,依赖注入 要理解上面两个概念,就必须搞清楚如下的问题: 参与者都有谁?依赖:谁依赖于谁?为什么需要依赖?注入:谁注入于谁?到底注入什么?控制反转:谁控制谁?控制什么?为什么叫反转(有反转就应该有正转了)?依赖注入和控制反转是同一概念吗? 下面就来简要地回答一下上述问题,把这些问题搞明白了,也就明白IoC/DI了.(1)参与者都有谁:一般有三方参与者,一个是某个对象:另一个是IoC/DI容器(

Spring中AOP主要用来做什么。Spring注入bean的方式。什么是IOC,什么是依赖注入

Spring中主要用到的设计模式有工厂模式和代理模式. IOC:Inversion of Control控制反转,也叫依赖注入,通过 sessionfactory 去注入实例:IOC就是一个生产和管理bean的容器就行了,原来需要在调用类中new的东西,现在都是通过容器生成,同时,要是产生的是单例的bean,他还可以给管理bean的生命周期:通过注解配置或者进行xml配置实现,如@Controller,@Service,@Repository等注解配置 AOP:提供了事务管理的能力.AOP面向切

IOC DI

IoC:Inversion of Control,控制反转DI:Dependency Injection,依赖注入 要理解上面两个概念,就必须搞清楚如下的问题: 参与者都有谁?依赖:谁依赖于谁?为什么需要依赖?注入:谁注入于谁?到底注入什么?控制反转:谁控制谁?控制什么?为什么叫反转(有反转就应该有正转了)?依赖注入和控制反转是同一概念吗? 下面就来简要地回答一下上述问题,把这些问题搞明白了,也就明白IoC/DI了.(1)参与者都有谁:一般有三方参与者,一个是某个对象:另一个是IoC/DI容器(